Compare commits
9 Commits
553b9b4952
...
73ad889018
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
73ad889018 | ||
|
|
9c7f1e4418 | ||
|
|
efb50916b2 | ||
|
|
6abb52694e | ||
|
|
76968e31a6 | ||
|
|
29bf0e6f1c | ||
|
|
8c306fbd23 | ||
|
|
b0c3baf5b7 | ||
|
|
f575588b9a |
4
.github/workflows/deploy.yml
vendored
4
.github/workflows/deploy.yml
vendored
@@ -43,9 +43,7 @@ jobs:
|
|||||||
bun-version: latest
|
bun-version: latest
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: |
|
run: bun install --frozen-lockfile
|
||||||
bun install --frozen-lockfile
|
|
||||||
cd web && bun install --frozen-lockfile
|
|
||||||
|
|
||||||
- name: Create Config File
|
- name: Create Config File
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
26
AGENTS.md
26
AGENTS.md
@@ -2,17 +2,16 @@
|
|||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
AuroraBot is a Discord bot with a web dashboard built using Bun, Discord.js, React, and PostgreSQL with Drizzle ORM.
|
AuroraBot is a Discord bot with a REST API built using Bun, Discord.js, and PostgreSQL with Drizzle ORM.
|
||||||
|
|
||||||
## Build/Lint/Test Commands
|
## Build/Lint/Test Commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Development
|
# Development
|
||||||
bun --watch bot/index.ts # Run bot with hot reload
|
bun --watch bot/index.ts # Run bot + API server with hot reload
|
||||||
bun --hot web/src/index.ts # Run web dashboard with hot reload
|
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
bun test # Run all tests ( expect some tests to fail when running all at once like this due to the nature of the tests )
|
bun test # Run all tests
|
||||||
bun test path/to/file.test.ts # Run single test file
|
bun test path/to/file.test.ts # Run single test file
|
||||||
bun test --watch # Watch mode
|
bun test --watch # Watch mode
|
||||||
bun test shared/modules/economy # Run tests in directory
|
bun test shared/modules/economy # Run tests in directory
|
||||||
@@ -24,9 +23,10 @@ bun run db:push # Push schema changes (Docker)
|
|||||||
bun run db:push:local # Push schema changes (local)
|
bun run db:push:local # Push schema changes (local)
|
||||||
bun run db:studio # Open Drizzle Studio
|
bun run db:studio # Open Drizzle Studio
|
||||||
|
|
||||||
# Web Dashboard
|
# Docker (recommended for local dev)
|
||||||
cd web && bun run build # Build production web assets
|
docker compose up # Start bot, API, and database
|
||||||
cd web && bun run dev # Development server
|
docker compose up app # Start just the app (bot + API)
|
||||||
|
docker compose up db # Start just the database
|
||||||
```
|
```
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
@@ -44,10 +44,8 @@ shared/ # Shared between bot and web
|
|||||||
├── lib/ # Utils, config, errors, types
|
├── lib/ # Utils, config, errors, types
|
||||||
└── modules/ # Domain services (economy, user, etc.)
|
└── modules/ # Domain services (economy, user, etc.)
|
||||||
|
|
||||||
web/ # React dashboard
|
web/ # API server
|
||||||
├── src/pages/ # React pages
|
└── src/routes/ # API route handlers
|
||||||
├── src/components/ # UI components (ShadCN/Radix)
|
|
||||||
└── src/hooks/ # React hooks
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Import Conventions
|
## Import Conventions
|
||||||
@@ -187,7 +185,7 @@ return await withTransaction(async (tx) => {
|
|||||||
|
|
||||||
- Use `bigint` mode for Discord IDs and currency amounts
|
- Use `bigint` mode for Discord IDs and currency amounts
|
||||||
- Relations defined separately from table definitions
|
- Relations defined separately from table definitions
|
||||||
- Schema location: `shared/db/schema.ts`
|
- Schema modules: `shared/db/schema/*.ts` (users, inventory, economy, quests, moderation)
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
@@ -224,9 +222,9 @@ describe("serviceName", () => {
|
|||||||
|
|
||||||
- **Runtime:** Bun 1.0+
|
- **Runtime:** Bun 1.0+
|
||||||
- **Bot:** Discord.js 14.x
|
- **Bot:** Discord.js 14.x
|
||||||
- **Web:** React 19 + Bun HTTP Server
|
- **Web:** Bun HTTP Server (REST API)
|
||||||
- **Database:** PostgreSQL 16+ with Drizzle ORM
|
- **Database:** PostgreSQL 16+ with Drizzle ORM
|
||||||
- **UI:** Tailwind CSS v4 + ShadCN/Radix
|
- **UI:** Discord embeds and components
|
||||||
- **Validation:** Zod
|
- **Validation:** Zod
|
||||||
- **Testing:** Bun Test
|
- **Testing:** Bun Test
|
||||||
- **Container:** Docker
|
- **Container:** Docker
|
||||||
|
|||||||
17
Dockerfile
17
Dockerfile
@@ -33,20 +33,3 @@ EXPOSE 3000
|
|||||||
|
|
||||||
# Default command
|
# Default command
|
||||||
CMD ["bun", "run", "dev"]
|
CMD ["bun", "run", "dev"]
|
||||||
|
|
||||||
# ============================================
|
|
||||||
# Production stage - full app with source code
|
|
||||||
# ============================================
|
|
||||||
FROM base AS production
|
|
||||||
|
|
||||||
# Copy dependencies from deps stage
|
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
|
||||||
|
|
||||||
# Copy source code
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Expose ports
|
|
||||||
EXPOSE 3000
|
|
||||||
|
|
||||||
# Default command
|
|
||||||
CMD ["bun", "run", "dev"]
|
|
||||||
|
|||||||
32
README.md
32
README.md
@@ -7,11 +7,9 @@
|
|||||||

|

|
||||||

|

|
||||||

|

|
||||||

|
|
||||||
|
|
||||||
Aurora is a powerful Discord bot designed to facilitate RPG-like elements within a Discord server. It features a robust economy, class system, inventory management, quests, and more, all built on top of a high-performance stack using Bun and Drizzle ORM.
|
Aurora is a powerful Discord bot designed to facilitate RPG-like elements within a Discord server. It features a robust economy, class system, inventory management, quests, and more, all built on top of a high-performance stack using Bun and Drizzle ORM.
|
||||||
|
|
||||||
**New in v1.0:** Aurora now includes a fully integrated **Web Dashboard** for managing the bot, viewing statistics, and configuring settings, running alongside the bot in a single process.
|
**New in v1.0:** Aurora now includes a fully integrated **REST API** for accessing bot data, statistics, and configuration, running alongside the bot in a single process.
|
||||||
|
|
||||||
## ✨ Features
|
## ✨ Features
|
||||||
|
|
||||||
@@ -25,26 +23,26 @@ Aurora is a powerful Discord bot designed to facilitate RPG-like elements within
|
|||||||
* **Lootdrops**: Random loot drops in channels to engage users.
|
* **Lootdrops**: Random loot drops in channels to engage users.
|
||||||
* **Admin Tools**: Administrative commands for server management.
|
* **Admin Tools**: Administrative commands for server management.
|
||||||
|
|
||||||
### Web Dashboard
|
### REST API
|
||||||
* **Live Analytics**: View real-time activity charts (commands, transactions).
|
* **Live Analytics**: Real-time statistics endpoint (commands, transactions).
|
||||||
* **Configuration Management**: Update bot settings without restarting.
|
* **Configuration Management**: Update bot settings via API.
|
||||||
* **Database Inspection**: Integrated Drizzle Studio access.
|
* **Database Inspection**: Integrated Drizzle Studio access.
|
||||||
* **State Monitoring**: View internal bot state (Lootdrops, etc.).
|
* **WebSocket Support**: Real-time event streaming for live updates.
|
||||||
|
|
||||||
## 🏗️ Architecture
|
## 🏗️ Architecture
|
||||||
|
|
||||||
Aurora uses a **Single Process Monolith** architecture to maximize performance and simplify resource sharing.
|
Aurora uses a **Single Process Monolith** architecture to maximize performance and simplify resource sharing.
|
||||||
|
|
||||||
* **Unified Runtime**: Both the Discord Client and the Web Dashboard run within the same Bun process.
|
* **Unified Runtime**: Both the Discord Client and the REST API run within the same Bun process.
|
||||||
* **Shared State**: This allows the Dashboard to access live bot memory (caches, gateways) directly without complex inter-process communication (IPC).
|
* **Shared State**: This allows the API to access live bot memory (caches, gateways) directly without complex inter-process communication (IPC).
|
||||||
* **Simplified Deployment**: You only need to deploy a single Docker container.
|
* **Simplified Deployment**: You only need to deploy a single Docker container.
|
||||||
|
|
||||||
## 🛠️ Tech Stack
|
## 🛠️ Tech Stack
|
||||||
|
|
||||||
* **Runtime**: [Bun](https://bun.sh/)
|
* **Runtime**: [Bun](https://bun.sh/)
|
||||||
* **Bot Framework**: [Discord.js](https://discord.js.org/)
|
* **Bot Framework**: [Discord.js](https://discord.js.org/)
|
||||||
* **Web Framework**: [React 19](https://react.dev/) + [Vite](https://vitejs.dev/) (served via Bun)
|
* **API Framework**: Bun HTTP Server (REST API)
|
||||||
* **Styling**: [Tailwind CSS v4](https://tailwindcss.com/) + [Radix UI](https://www.radix-ui.com/)
|
* **UI**: Discord embeds and components
|
||||||
* **Database**: [PostgreSQL](https://www.postgresql.org/)
|
* **Database**: [PostgreSQL](https://www.postgresql.org/)
|
||||||
* **ORM**: [Drizzle ORM](https://orm.drizzle.team/)
|
* **ORM**: [Drizzle ORM](https://orm.drizzle.team/)
|
||||||
* **Validation**: [Zod](https://zod.dev/)
|
* **Validation**: [Zod](https://zod.dev/)
|
||||||
@@ -94,14 +92,14 @@ Aurora uses a **Single Process Monolith** architecture to maximize performance a
|
|||||||
bun run db:push
|
bun run db:push
|
||||||
```
|
```
|
||||||
|
|
||||||
### Running the Bot & Dashboard
|
### Running the Bot & API
|
||||||
|
|
||||||
**Development Mode** (with hot reload):
|
**Development Mode** (with hot reload):
|
||||||
```bash
|
```bash
|
||||||
bun run dev
|
bun run dev
|
||||||
```
|
```
|
||||||
* Bot: Online in Discord
|
* Bot: Online in Discord
|
||||||
* Dashboard: http://localhost:3000
|
* API: http://localhost:3000
|
||||||
|
|
||||||
**Production Mode**:
|
**Production Mode**:
|
||||||
Build and run with Docker (recommended):
|
Build and run with Docker (recommended):
|
||||||
@@ -111,7 +109,7 @@ docker compose up -d app
|
|||||||
|
|
||||||
### 🔐 Accessing Production Services (SSH Tunnel)
|
### 🔐 Accessing Production Services (SSH Tunnel)
|
||||||
|
|
||||||
For security, the Production Database and Dashboard are **not exposed** to the public internet by default. They are only accessible via localhost on the server.
|
For security, the Production Database and API are **not exposed** to the public internet by default. They are only accessible via localhost on the server.
|
||||||
|
|
||||||
To access them from your local machine, use the included SSH tunnel script.
|
To access them from your local machine, use the included SSH tunnel script.
|
||||||
|
|
||||||
@@ -127,12 +125,12 @@ To access them from your local machine, use the included SSH tunnel script.
|
|||||||
```
|
```
|
||||||
|
|
||||||
This will establish secure tunnels for:
|
This will establish secure tunnels for:
|
||||||
* **Dashboard**: http://localhost:3000
|
* **API**: http://localhost:3000
|
||||||
* **Drizzle Studio**: http://localhost:4983
|
* **Drizzle Studio**: http://localhost:4983
|
||||||
|
|
||||||
## 📜 Scripts
|
## 📜 Scripts
|
||||||
|
|
||||||
* `bun run dev`: Start the bot and dashboard in watch mode.
|
* `bun run dev`: Start the bot and API server in watch mode.
|
||||||
* `bun run remote`: Open SSH tunnel to production services.
|
* `bun run remote`: Open SSH tunnel to production services.
|
||||||
* `bun run generate`: Generate Drizzle migrations.
|
* `bun run generate`: Generate Drizzle migrations.
|
||||||
* `bun run migrate`: Apply migrations (via Docker).
|
* `bun run migrate`: Apply migrations (via Docker).
|
||||||
@@ -143,7 +141,7 @@ This will establish secure tunnels for:
|
|||||||
|
|
||||||
```
|
```
|
||||||
├── bot # Discord Bot logic & entry point
|
├── bot # Discord Bot logic & entry point
|
||||||
├── web # React Web Dashboard (Frontend + Server)
|
├── web # REST API Server
|
||||||
├── shared # Shared code (Database, Config, Types)
|
├── shared # Shared code (Database, Config, Types)
|
||||||
├── drizzle # Drizzle migration files
|
├── drizzle # Drizzle migration files
|
||||||
├── scripts # Utility scripts
|
├── scripts # Utility scripts
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { levelingService } from "@shared/modules/leveling/leveling.service";
|
import { levelingService } from "@shared/modules/leveling/leveling.service";
|
||||||
import { economyService } from "@shared/modules/economy/economy.service";
|
import { economyService } from "@shared/modules/economy/economy.service";
|
||||||
import { userTimers } from "@db/schema";
|
import { userTimers } from "@db/schema";
|
||||||
import type { EffectHandler } from "./types";
|
import type { EffectHandler } from "./effect.types";
|
||||||
import type { LootTableItem } from "@shared/lib/types";
|
import type { LootTableItem } from "@shared/lib/types";
|
||||||
import { inventoryService } from "@shared/modules/inventory/inventory.service";
|
import { inventoryService } from "@shared/modules/inventory/inventory.service";
|
||||||
import { inventory, items } from "@db/schema";
|
import { inventory, items } from "@db/schema";
|
||||||
@@ -6,8 +6,8 @@ import {
|
|||||||
handleTempRole,
|
handleTempRole,
|
||||||
handleColorRole,
|
handleColorRole,
|
||||||
handleLootbox
|
handleLootbox
|
||||||
} from "./handlers";
|
} from "./effect.handlers";
|
||||||
import type { EffectHandler } from "./types";
|
import type { EffectHandler } from "./effect.types";
|
||||||
|
|
||||||
export const effectHandlers: Record<string, EffectHandler> = {
|
export const effectHandlers: Record<string, EffectHandler> = {
|
||||||
'ADD_XP': handleAddXp,
|
'ADD_XP': handleAddXp,
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import type { Transaction } from "@shared/lib/types";
|
import type { Transaction } from "@shared/lib/types";
|
||||||
|
|
||||||
export type EffectHandler = (userId: string, effect: any, txFn: Transaction) => Promise<any>;
|
export type EffectHandler = (userId: string, effect: any, txFn: Transaction) => Promise<any>;
|
||||||
10
bun.lock
10
bun.lock
@@ -5,19 +5,19 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "app",
|
"name": "app",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@napi-rs/canvas": "^0.1.84",
|
"@napi-rs/canvas": "^0.1.89",
|
||||||
"discord.js": "^14.25.1",
|
"discord.js": "^14.25.1",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"drizzle-orm": "^0.44.7",
|
"drizzle-orm": "^0.44.7",
|
||||||
"postgres": "^3.4.7",
|
"postgres": "^3.4.8",
|
||||||
"zod": "^4.1.13",
|
"zod": "^4.3.6",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "latest",
|
"@types/bun": "latest",
|
||||||
"drizzle-kit": "^0.31.7",
|
"drizzle-kit": "^0.31.8",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "^5",
|
"typescript": "^5.9.3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
52
docs/main.md
52
docs/main.md
@@ -4,7 +4,7 @@ A comprehensive, feature-rich Discord RPG bot built with modern technologies usi
|
|||||||
|
|
||||||
## Architecture Overview
|
## Architecture Overview
|
||||||
|
|
||||||
Aurora uses a **Single Process Monolith** architecture that runs both the Discord bot and web dashboard in the same Bun process. This design maximizes performance by eliminating inter-process communication overhead and simplifies deployment to a single Docker container.
|
Aurora uses a **Single Process Monolith** architecture that runs both the Discord bot and REST API in the same Bun process. This design maximizes performance by eliminating inter-process communication overhead and simplifies deployment to a single Docker container.
|
||||||
|
|
||||||
## Monorepo Structure
|
## Monorepo Structure
|
||||||
|
|
||||||
@@ -15,12 +15,8 @@ aurora-bot-discord/
|
|||||||
│ ├── events/ # Discord event handlers
|
│ ├── events/ # Discord event handlers
|
||||||
│ ├── lib/ # Bot core logic (BotClient, utilities)
|
│ ├── lib/ # Bot core logic (BotClient, utilities)
|
||||||
│ └── index.ts # Bot entry point
|
│ └── index.ts # Bot entry point
|
||||||
├── web/ # React web dashboard
|
├── web/ # REST API server
|
||||||
│ ├── src/ # React components and pages
|
│ └── src/routes/ # API route handlers
|
||||||
│ │ ├── pages/ # Dashboard pages (Admin, Settings, Home)
|
|
||||||
│ │ ├── components/ # Reusable UI components
|
|
||||||
│ │ └── server.ts # Web server with API endpoints
|
|
||||||
│ └── build.ts # Vite build configuration
|
|
||||||
├── shared/ # Shared code between bot and web
|
├── shared/ # Shared code between bot and web
|
||||||
│ ├── db/ # Database schema and Drizzle ORM
|
│ ├── db/ # Database schema and Drizzle ORM
|
||||||
│ ├── lib/ # Utilities, config, logger, events
|
│ ├── lib/ # Utilities, config, logger, events
|
||||||
@@ -52,28 +48,26 @@ The bot is built with Discord.js v14 and handles all Discord-related functionali
|
|||||||
- `ready.ts`: Bot ready events
|
- `ready.ts`: Bot ready events
|
||||||
- `guildMemberAdd.ts`: New member handling
|
- `guildMemberAdd.ts`: New member handling
|
||||||
|
|
||||||
### 2. Web Dashboard (`web/`)
|
### 2. REST API (`web/`)
|
||||||
|
|
||||||
A React 19 + Bun web application for bot administration and monitoring.
|
A headless REST API built with Bun's native HTTP server for bot administration and data access.
|
||||||
|
|
||||||
**Key Pages:**
|
**Key Endpoints:**
|
||||||
|
|
||||||
- **Home** (`/`): Dashboard overview with live statistics
|
- **Stats** (`/api/stats`): Real-time bot metrics and statistics
|
||||||
- **Admin Overview** (`/admin/overview`): Real-time bot metrics
|
- **Settings** (`/api/settings`): Configuration management endpoints
|
||||||
- **Admin Quests** (`/admin/quests`): Quest management interface
|
- **Users** (`/api/users`): User data and profiles
|
||||||
- **Settings** (`/settings/*`): Configuration pages for:
|
- **Items** (`/api/items`): Item catalog and management
|
||||||
- General settings
|
- **Quests** (`/api/quests`): Quest data and progress
|
||||||
- Economy settings
|
- **Economy** (`/api/transactions`): Economy and transaction data
|
||||||
- Systems settings
|
|
||||||
- Roles settings
|
|
||||||
|
|
||||||
**Web Server Features:**
|
**API Features:**
|
||||||
|
|
||||||
- Built with Bun's native HTTP server
|
- Built with Bun's native HTTP server
|
||||||
- WebSocket support for real-time updates
|
- WebSocket support for real-time updates (`/ws`)
|
||||||
- REST API endpoints for dashboard data
|
- REST API endpoints for all bot data
|
||||||
- SPA fallback for client-side routing
|
- Real-time event streaming via WebSocket
|
||||||
- Bun dev server with hot module replacement
|
- Zod validation for all requests
|
||||||
|
|
||||||
### 3. Shared Core (`shared/`)
|
### 3. Shared Core (`shared/`)
|
||||||
|
|
||||||
@@ -123,15 +117,15 @@ Shared code accessible by both bot and web applications.
|
|||||||
|
|
||||||
### For Server Administrators
|
### For Server Administrators
|
||||||
|
|
||||||
1. **Bot Configuration**: Adjust economy rates, enable/disable features via dashboard
|
1. **Bot Configuration**: Adjust economy rates, enable/disable features via API
|
||||||
2. **Moderation Tools**:
|
2. **Moderation Tools**:
|
||||||
- Warn, note, and track moderation cases
|
- Warn, note, and track moderation cases
|
||||||
- Mass prune inactive members
|
- Mass prune inactive members
|
||||||
- Role management
|
- Role management
|
||||||
3. **Quest Management**: Create and manage server-specific quests
|
3. **Quest Management**: Create and manage server-specific quests
|
||||||
4. **Monitoring**:
|
4. **Monitoring**:
|
||||||
- Real-time dashboard with live statistics
|
- Real-time statistics via REST API
|
||||||
- Activity charts and event logs
|
- Activity data and event logs
|
||||||
- Economy leaderboards
|
- Economy leaderboards
|
||||||
|
|
||||||
### For Developers
|
### For Developers
|
||||||
@@ -148,10 +142,10 @@ Shared code accessible by both bot and web applications.
|
|||||||
| ---------------- | --------------------------------- |
|
| ---------------- | --------------------------------- |
|
||||||
| Runtime | Bun 1.0+ |
|
| Runtime | Bun 1.0+ |
|
||||||
| Bot Framework | Discord.js 14.x |
|
| Bot Framework | Discord.js 14.x |
|
||||||
| Web Framework | React 19 + Bun |
|
| Web Framework | Bun HTTP Server (REST API) |
|
||||||
| Database | PostgreSQL 17 |
|
| Database | PostgreSQL 17 |
|
||||||
| ORM | Drizzle ORM |
|
| ORM | Drizzle ORM |
|
||||||
| Styling | Tailwind CSS v4 + ShadCN/Radix UI |
|
| UI | Discord embeds and components |
|
||||||
| Validation | Zod |
|
| Validation | Zod |
|
||||||
| Containerization | Docker |
|
| Containerization | Docker |
|
||||||
|
|
||||||
@@ -165,4 +159,4 @@ bun run migrate
|
|||||||
docker compose up
|
docker compose up
|
||||||
```
|
```
|
||||||
|
|
||||||
The bot and dashboard process run on port 3000 and are accessible at `http://localhost:3000`.
|
The bot and API server run on port 3000 and are accessible at `http://localhost:3000`.
|
||||||
|
|||||||
@@ -1,270 +1,3 @@
|
|||||||
import {
|
// Re-export all schema definitions from domain modules
|
||||||
pgTable,
|
// This file is kept for backward compatibility
|
||||||
bigint,
|
export * from './schema/index';
|
||||||
varchar,
|
|
||||||
boolean,
|
|
||||||
jsonb,
|
|
||||||
timestamp,
|
|
||||||
serial,
|
|
||||||
text,
|
|
||||||
integer,
|
|
||||||
primaryKey,
|
|
||||||
index,
|
|
||||||
bigserial,
|
|
||||||
check
|
|
||||||
} from 'drizzle-orm/pg-core';
|
|
||||||
import { relations, sql, type InferSelectModel } from 'drizzle-orm';
|
|
||||||
|
|
||||||
export type User = InferSelectModel<typeof users>;
|
|
||||||
export type Transaction = InferSelectModel<typeof transactions>;
|
|
||||||
export type ModerationCase = InferSelectModel<typeof moderationCases>;
|
|
||||||
export type Item = InferSelectModel<typeof items>;
|
|
||||||
export type Inventory = InferSelectModel<typeof inventory>;
|
|
||||||
|
|
||||||
// --- TABLES ---
|
|
||||||
|
|
||||||
// 1. Classes
|
|
||||||
export const classes = pgTable('classes', {
|
|
||||||
id: bigint('id', { mode: 'bigint' }).primaryKey(),
|
|
||||||
name: varchar('name', { length: 255 }).unique().notNull(),
|
|
||||||
balance: bigint('balance', { mode: 'bigint' }).default(0n),
|
|
||||||
roleId: varchar('role_id', { length: 255 }),
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2. Users
|
|
||||||
export const users = pgTable('users', {
|
|
||||||
id: bigint('id', { mode: 'bigint' }).primaryKey(),
|
|
||||||
classId: bigint('class_id', { mode: 'bigint' }).references(() => classes.id),
|
|
||||||
username: varchar('username', { length: 255 }).unique().notNull(),
|
|
||||||
isActive: boolean('is_active').default(true),
|
|
||||||
|
|
||||||
// Economy
|
|
||||||
balance: bigint('balance', { mode: 'bigint' }).default(0n),
|
|
||||||
xp: bigint('xp', { mode: 'bigint' }).default(0n),
|
|
||||||
level: integer('level').default(1),
|
|
||||||
dailyStreak: integer('daily_streak').default(0),
|
|
||||||
|
|
||||||
// Metadata
|
|
||||||
settings: jsonb('settings').default({}),
|
|
||||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
|
|
||||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow(),
|
|
||||||
}, (table) => [
|
|
||||||
index('users_username_idx').on(table.username),
|
|
||||||
index('users_balance_idx').on(table.balance),
|
|
||||||
index('users_level_xp_idx').on(table.level, table.xp),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 3. Items
|
|
||||||
export const items = pgTable('items', {
|
|
||||||
id: serial('id').primaryKey(),
|
|
||||||
name: varchar('name', { length: 255 }).unique().notNull(),
|
|
||||||
description: text('description'),
|
|
||||||
rarity: varchar('rarity', { length: 20 }).default('C'),
|
|
||||||
|
|
||||||
// Economy & Visuals
|
|
||||||
type: varchar('type', { length: 50 }).notNull().default('MATERIAL'),
|
|
||||||
// Examples: 'CONSUMABLE', 'EQUIPMENT', 'MATERIAL'
|
|
||||||
usageData: jsonb('usage_data').default({}),
|
|
||||||
price: bigint('price', { mode: 'bigint' }),
|
|
||||||
iconUrl: text('icon_url').notNull(),
|
|
||||||
imageUrl: text('image_url').notNull(),
|
|
||||||
});
|
|
||||||
|
|
||||||
// 4. Inventory (Join Table)
|
|
||||||
export const inventory = pgTable('inventory', {
|
|
||||||
userId: bigint('user_id', { mode: 'bigint' })
|
|
||||||
.references(() => users.id, { onDelete: 'cascade' }).notNull(),
|
|
||||||
itemId: integer('item_id')
|
|
||||||
.references(() => items.id, { onDelete: 'cascade' }).notNull(),
|
|
||||||
quantity: bigint('quantity', { mode: 'bigint' }).default(1n),
|
|
||||||
}, (table) => [
|
|
||||||
primaryKey({ columns: [table.userId, table.itemId] }),
|
|
||||||
check('quantity_check', sql`${table.quantity} > 0`)
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 5. Transactions
|
|
||||||
export const transactions = pgTable('transactions', {
|
|
||||||
id: bigserial('id', { mode: 'bigint' }).primaryKey(),
|
|
||||||
userId: bigint('user_id', { mode: 'bigint' })
|
|
||||||
.references(() => users.id, { onDelete: 'cascade' }),
|
|
||||||
relatedUserId: bigint('related_user_id', { mode: 'bigint' })
|
|
||||||
.references(() => users.id, { onDelete: 'set null' }),
|
|
||||||
amount: bigint('amount', { mode: 'bigint' }).notNull(),
|
|
||||||
type: varchar('type', { length: 50 }).notNull(),
|
|
||||||
description: text('description'),
|
|
||||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
|
|
||||||
}, (table) => [
|
|
||||||
index('transactions_created_at_idx').on(table.createdAt),
|
|
||||||
]);
|
|
||||||
|
|
||||||
export const itemTransactions = pgTable('item_transactions', {
|
|
||||||
id: bigserial('id', { mode: 'bigint' }).primaryKey(),
|
|
||||||
userId: bigint('user_id', { mode: 'bigint' })
|
|
||||||
.references(() => users.id, { onDelete: 'cascade' }).notNull(),
|
|
||||||
relatedUserId: bigint('related_user_id', { mode: 'bigint' })
|
|
||||||
.references(() => users.id, { onDelete: 'set null' }), // who they got it from/gave it to
|
|
||||||
itemId: integer('item_id')
|
|
||||||
.references(() => items.id, { onDelete: 'cascade' }).notNull(),
|
|
||||||
quantity: bigint('quantity', { mode: 'bigint' }).notNull(), // positive = gain, negative = loss
|
|
||||||
type: varchar('type', { length: 50 }).notNull(), // e.g., 'TRADE', 'SHOP_BUY', 'DROP'
|
|
||||||
description: text('description'),
|
|
||||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
|
|
||||||
});
|
|
||||||
|
|
||||||
// 6. Quests
|
|
||||||
export const quests = pgTable('quests', {
|
|
||||||
id: serial('id').primaryKey(),
|
|
||||||
name: varchar('name', { length: 255 }).notNull(),
|
|
||||||
description: text('description'),
|
|
||||||
triggerEvent: varchar('trigger_event', { length: 50 }).notNull(),
|
|
||||||
requirements: jsonb('requirements').notNull().default({}),
|
|
||||||
rewards: jsonb('rewards').notNull().default({}),
|
|
||||||
});
|
|
||||||
|
|
||||||
// 7. User Quests (Join Table)
|
|
||||||
export const userQuests = pgTable('user_quests', {
|
|
||||||
userId: bigint('user_id', { mode: 'bigint' })
|
|
||||||
.references(() => users.id, { onDelete: 'cascade' }).notNull(),
|
|
||||||
questId: integer('quest_id')
|
|
||||||
.references(() => quests.id, { onDelete: 'cascade' }).notNull(),
|
|
||||||
progress: integer('progress').default(0),
|
|
||||||
completedAt: timestamp('completed_at', { withTimezone: true }),
|
|
||||||
}, (table) => [
|
|
||||||
primaryKey({ columns: [table.userId, table.questId] })
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 8. User Timers (Generic: Cooldowns, Effects, Access)
|
|
||||||
export const userTimers = pgTable('user_timers', {
|
|
||||||
userId: bigint('user_id', { mode: 'bigint' })
|
|
||||||
.references(() => users.id, { onDelete: 'cascade' }).notNull(),
|
|
||||||
type: varchar('type', { length: 50 }).notNull(), // 'COOLDOWN', 'EFFECT', 'ACCESS'
|
|
||||||
key: varchar('key', { length: 100 }).notNull(), // 'daily', 'chn_12345', 'xp_boost'
|
|
||||||
expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
|
|
||||||
metadata: jsonb('metadata').default({}), // Store channelId, specific buff amounts, etc.
|
|
||||||
}, (table) => [
|
|
||||||
primaryKey({ columns: [table.userId, table.type, table.key] }),
|
|
||||||
index('user_timers_expires_at_idx').on(table.expiresAt),
|
|
||||||
index('user_timers_lookup_idx').on(table.userId, table.type, table.key),
|
|
||||||
]);
|
|
||||||
// 9. Lootdrops
|
|
||||||
export const lootdrops = pgTable('lootdrops', {
|
|
||||||
messageId: varchar('message_id', { length: 255 }).primaryKey(),
|
|
||||||
channelId: varchar('channel_id', { length: 255 }).notNull(),
|
|
||||||
rewardAmount: integer('reward_amount').notNull(),
|
|
||||||
currency: varchar('currency', { length: 50 }).notNull(),
|
|
||||||
claimedBy: bigint('claimed_by', { mode: 'bigint' }).references(() => users.id, { onDelete: 'set null' }),
|
|
||||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
|
||||||
expiresAt: timestamp('expires_at', { withTimezone: true }),
|
|
||||||
});
|
|
||||||
|
|
||||||
// 10. Moderation Cases
|
|
||||||
export const moderationCases = pgTable('moderation_cases', {
|
|
||||||
id: bigserial('id', { mode: 'bigint' }).primaryKey(),
|
|
||||||
caseId: varchar('case_id', { length: 50 }).unique().notNull(),
|
|
||||||
type: varchar('type', { length: 20 }).notNull(), // 'warn', 'timeout', 'kick', 'ban', 'note', 'prune'
|
|
||||||
userId: bigint('user_id', { mode: 'bigint' }).notNull(),
|
|
||||||
username: varchar('username', { length: 255 }).notNull(),
|
|
||||||
moderatorId: bigint('moderator_id', { mode: 'bigint' }).notNull(),
|
|
||||||
moderatorName: varchar('moderator_name', { length: 255 }).notNull(),
|
|
||||||
reason: text('reason').notNull(),
|
|
||||||
metadata: jsonb('metadata').default({}),
|
|
||||||
active: boolean('active').default(true).notNull(),
|
|
||||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
|
||||||
resolvedAt: timestamp('resolved_at', { withTimezone: true }),
|
|
||||||
resolvedBy: bigint('resolved_by', { mode: 'bigint' }),
|
|
||||||
resolvedReason: text('resolved_reason'),
|
|
||||||
}, (table) => [
|
|
||||||
index('moderation_cases_user_id_idx').on(table.userId),
|
|
||||||
index('moderation_cases_case_id_idx').on(table.caseId),
|
|
||||||
]);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const classesRelations = relations(classes, ({ many }) => ({
|
|
||||||
users: many(users),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const usersRelations = relations(users, ({ one, many }) => ({
|
|
||||||
class: one(classes, {
|
|
||||||
fields: [users.classId],
|
|
||||||
references: [classes.id],
|
|
||||||
}),
|
|
||||||
inventory: many(inventory),
|
|
||||||
transactions: many(transactions),
|
|
||||||
quests: many(userQuests),
|
|
||||||
timers: many(userTimers),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const itemsRelations = relations(items, ({ many }) => ({
|
|
||||||
inventoryEntries: many(inventory),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const inventoryRelations = relations(inventory, ({ one }) => ({
|
|
||||||
user: one(users, {
|
|
||||||
fields: [inventory.userId],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
item: one(items, {
|
|
||||||
fields: [inventory.itemId],
|
|
||||||
references: [items.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const transactionsRelations = relations(transactions, ({ one }) => ({
|
|
||||||
user: one(users, {
|
|
||||||
fields: [transactions.userId],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const questsRelations = relations(quests, ({ many }) => ({
|
|
||||||
userEntries: many(userQuests),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const userQuestsRelations = relations(userQuests, ({ one }) => ({
|
|
||||||
user: one(users, {
|
|
||||||
fields: [userQuests.userId],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
quest: one(quests, {
|
|
||||||
fields: [userQuests.questId],
|
|
||||||
references: [quests.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const userTimersRelations = relations(userTimers, ({ one }) => ({
|
|
||||||
user: one(users, {
|
|
||||||
fields: [userTimers.userId],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const itemTransactionsRelations = relations(itemTransactions, ({ one }) => ({
|
|
||||||
user: one(users, {
|
|
||||||
fields: [itemTransactions.userId],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
relatedUser: one(users, {
|
|
||||||
fields: [itemTransactions.relatedUserId],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
item: one(items, {
|
|
||||||
fields: [itemTransactions.itemId],
|
|
||||||
references: [items.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const moderationCasesRelations = relations(moderationCases, ({ one }) => ({
|
|
||||||
user: one(users, {
|
|
||||||
fields: [moderationCases.userId],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
moderator: one(users, {
|
|
||||||
fields: [moderationCases.moderatorId],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
resolver: one(users, {
|
|
||||||
fields: [moderationCases.resolvedBy],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|||||||
69
shared/db/schema/economy.ts
Normal file
69
shared/db/schema/economy.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import {
|
||||||
|
pgTable,
|
||||||
|
bigint,
|
||||||
|
varchar,
|
||||||
|
text,
|
||||||
|
timestamp,
|
||||||
|
bigserial,
|
||||||
|
index,
|
||||||
|
integer,
|
||||||
|
} from 'drizzle-orm/pg-core';
|
||||||
|
import { relations, type InferSelectModel } from 'drizzle-orm';
|
||||||
|
import { users } from './users';
|
||||||
|
import { items } from './inventory';
|
||||||
|
|
||||||
|
// --- TYPES ---
|
||||||
|
export type Transaction = InferSelectModel<typeof transactions>;
|
||||||
|
export type ItemTransaction = InferSelectModel<typeof itemTransactions>;
|
||||||
|
|
||||||
|
// --- TABLES ---
|
||||||
|
export const transactions = pgTable('transactions', {
|
||||||
|
id: bigserial('id', { mode: 'bigint' }).primaryKey(),
|
||||||
|
userId: bigint('user_id', { mode: 'bigint' })
|
||||||
|
.references(() => users.id, { onDelete: 'cascade' }),
|
||||||
|
relatedUserId: bigint('related_user_id', { mode: 'bigint' })
|
||||||
|
.references(() => users.id, { onDelete: 'set null' }),
|
||||||
|
amount: bigint('amount', { mode: 'bigint' }).notNull(),
|
||||||
|
type: varchar('type', { length: 50 }).notNull(),
|
||||||
|
description: text('description'),
|
||||||
|
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
|
||||||
|
}, (table) => [
|
||||||
|
index('transactions_created_at_idx').on(table.createdAt),
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const itemTransactions = pgTable('item_transactions', {
|
||||||
|
id: bigserial('id', { mode: 'bigint' }).primaryKey(),
|
||||||
|
userId: bigint('user_id', { mode: 'bigint' })
|
||||||
|
.references(() => users.id, { onDelete: 'cascade' }).notNull(),
|
||||||
|
relatedUserId: bigint('related_user_id', { mode: 'bigint' })
|
||||||
|
.references(() => users.id, { onDelete: 'set null' }),
|
||||||
|
itemId: integer('item_id')
|
||||||
|
.references(() => items.id, { onDelete: 'cascade' }).notNull(),
|
||||||
|
quantity: bigint('quantity', { mode: 'bigint' }).notNull(),
|
||||||
|
type: varchar('type', { length: 50 }).notNull(), // e.g., 'TRADE', 'SHOP_BUY', 'DROP'
|
||||||
|
description: text('description'),
|
||||||
|
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- RELATIONS ---
|
||||||
|
export const transactionsRelations = relations(transactions, ({ one }) => ({
|
||||||
|
user: one(users, {
|
||||||
|
fields: [transactions.userId],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const itemTransactionsRelations = relations(itemTransactions, ({ one }) => ({
|
||||||
|
user: one(users, {
|
||||||
|
fields: [itemTransactions.userId],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
relatedUser: one(users, {
|
||||||
|
fields: [itemTransactions.relatedUserId],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
item: one(items, {
|
||||||
|
fields: [itemTransactions.itemId],
|
||||||
|
references: [items.id],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
6
shared/db/schema/index.ts
Normal file
6
shared/db/schema/index.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// Domain modules
|
||||||
|
export * from './users';
|
||||||
|
export * from './inventory';
|
||||||
|
export * from './economy';
|
||||||
|
export * from './quests';
|
||||||
|
export * from './moderation';
|
||||||
57
shared/db/schema/inventory.ts
Normal file
57
shared/db/schema/inventory.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import {
|
||||||
|
pgTable,
|
||||||
|
bigint,
|
||||||
|
varchar,
|
||||||
|
serial,
|
||||||
|
text,
|
||||||
|
integer,
|
||||||
|
jsonb,
|
||||||
|
primaryKey,
|
||||||
|
check,
|
||||||
|
} from 'drizzle-orm/pg-core';
|
||||||
|
import { relations, sql, type InferSelectModel } from 'drizzle-orm';
|
||||||
|
import { users } from './users';
|
||||||
|
|
||||||
|
// --- TYPES ---
|
||||||
|
export type Item = InferSelectModel<typeof items>;
|
||||||
|
export type Inventory = InferSelectModel<typeof inventory>;
|
||||||
|
|
||||||
|
// --- TABLES ---
|
||||||
|
export const items = pgTable('items', {
|
||||||
|
id: serial('id').primaryKey(),
|
||||||
|
name: varchar('name', { length: 255 }).unique().notNull(),
|
||||||
|
description: text('description'),
|
||||||
|
rarity: varchar('rarity', { length: 20 }).default('C'),
|
||||||
|
type: varchar('type', { length: 50 }).notNull().default('MATERIAL'),
|
||||||
|
usageData: jsonb('usage_data').default({}),
|
||||||
|
price: bigint('price', { mode: 'bigint' }),
|
||||||
|
iconUrl: text('icon_url').notNull(),
|
||||||
|
imageUrl: text('image_url').notNull(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const inventory = pgTable('inventory', {
|
||||||
|
userId: bigint('user_id', { mode: 'bigint' })
|
||||||
|
.references(() => users.id, { onDelete: 'cascade' }).notNull(),
|
||||||
|
itemId: integer('item_id')
|
||||||
|
.references(() => items.id, { onDelete: 'cascade' }).notNull(),
|
||||||
|
quantity: bigint('quantity', { mode: 'bigint' }).default(1n),
|
||||||
|
}, (table) => [
|
||||||
|
primaryKey({ columns: [table.userId, table.itemId] }),
|
||||||
|
check('quantity_check', sql`${table.quantity} > 0`)
|
||||||
|
]);
|
||||||
|
|
||||||
|
// --- RELATIONS ---
|
||||||
|
export const itemsRelations = relations(items, ({ many }) => ({
|
||||||
|
inventoryEntries: many(inventory),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const inventoryRelations = relations(inventory, ({ one }) => ({
|
||||||
|
user: one(users, {
|
||||||
|
fields: [inventory.userId],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
item: one(items, {
|
||||||
|
fields: [inventory.itemId],
|
||||||
|
references: [items.id],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
65
shared/db/schema/moderation.ts
Normal file
65
shared/db/schema/moderation.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import {
|
||||||
|
pgTable,
|
||||||
|
bigint,
|
||||||
|
varchar,
|
||||||
|
text,
|
||||||
|
jsonb,
|
||||||
|
timestamp,
|
||||||
|
boolean,
|
||||||
|
bigserial,
|
||||||
|
integer,
|
||||||
|
index,
|
||||||
|
} from 'drizzle-orm/pg-core';
|
||||||
|
import { relations, type InferSelectModel } from 'drizzle-orm';
|
||||||
|
import { users } from './users';
|
||||||
|
|
||||||
|
// --- TYPES ---
|
||||||
|
export type ModerationCase = InferSelectModel<typeof moderationCases>;
|
||||||
|
export type Lootdrop = InferSelectModel<typeof lootdrops>;
|
||||||
|
|
||||||
|
// --- TABLES ---
|
||||||
|
export const moderationCases = pgTable('moderation_cases', {
|
||||||
|
id: bigserial('id', { mode: 'bigint' }).primaryKey(),
|
||||||
|
caseId: varchar('case_id', { length: 50 }).unique().notNull(),
|
||||||
|
type: varchar('type', { length: 20 }).notNull(), // 'warn', 'timeout', 'kick', 'ban', 'note', 'prune'
|
||||||
|
userId: bigint('user_id', { mode: 'bigint' }).notNull(),
|
||||||
|
username: varchar('username', { length: 255 }).notNull(),
|
||||||
|
moderatorId: bigint('moderator_id', { mode: 'bigint' }).notNull(),
|
||||||
|
moderatorName: varchar('moderator_name', { length: 255 }).notNull(),
|
||||||
|
reason: text('reason').notNull(),
|
||||||
|
metadata: jsonb('metadata').default({}),
|
||||||
|
active: boolean('active').default(true).notNull(),
|
||||||
|
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||||
|
resolvedAt: timestamp('resolved_at', { withTimezone: true }),
|
||||||
|
resolvedBy: bigint('resolved_by', { mode: 'bigint' }),
|
||||||
|
resolvedReason: text('resolved_reason'),
|
||||||
|
}, (table) => [
|
||||||
|
index('moderation_cases_user_id_idx').on(table.userId),
|
||||||
|
index('moderation_cases_case_id_idx').on(table.caseId),
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const lootdrops = pgTable('lootdrops', {
|
||||||
|
messageId: varchar('message_id', { length: 255 }).primaryKey(),
|
||||||
|
channelId: varchar('channel_id', { length: 255 }).notNull(),
|
||||||
|
rewardAmount: integer('reward_amount').notNull(),
|
||||||
|
currency: varchar('currency', { length: 50 }).notNull(),
|
||||||
|
claimedBy: bigint('claimed_by', { mode: 'bigint' }).references(() => users.id, { onDelete: 'set null' }),
|
||||||
|
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||||
|
expiresAt: timestamp('expires_at', { withTimezone: true }),
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- RELATIONS ---
|
||||||
|
export const moderationCasesRelations = relations(moderationCases, ({ one }) => ({
|
||||||
|
user: one(users, {
|
||||||
|
fields: [moderationCases.userId],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
moderator: one(users, {
|
||||||
|
fields: [moderationCases.moderatorId],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
resolver: one(users, {
|
||||||
|
fields: [moderationCases.resolvedBy],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
54
shared/db/schema/quests.ts
Normal file
54
shared/db/schema/quests.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import {
|
||||||
|
pgTable,
|
||||||
|
bigint,
|
||||||
|
varchar,
|
||||||
|
serial,
|
||||||
|
text,
|
||||||
|
jsonb,
|
||||||
|
timestamp,
|
||||||
|
integer,
|
||||||
|
primaryKey,
|
||||||
|
} from 'drizzle-orm/pg-core';
|
||||||
|
import { relations, type InferSelectModel } from 'drizzle-orm';
|
||||||
|
import { users } from './users';
|
||||||
|
|
||||||
|
// --- TYPES ---
|
||||||
|
export type Quest = InferSelectModel<typeof quests>;
|
||||||
|
export type UserQuest = InferSelectModel<typeof userQuests>;
|
||||||
|
|
||||||
|
// --- TABLES ---
|
||||||
|
export const quests = pgTable('quests', {
|
||||||
|
id: serial('id').primaryKey(),
|
||||||
|
name: varchar('name', { length: 255 }).notNull(),
|
||||||
|
description: text('description'),
|
||||||
|
triggerEvent: varchar('trigger_event', { length: 50 }).notNull(),
|
||||||
|
requirements: jsonb('requirements').notNull().default({}),
|
||||||
|
rewards: jsonb('rewards').notNull().default({}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const userQuests = pgTable('user_quests', {
|
||||||
|
userId: bigint('user_id', { mode: 'bigint' })
|
||||||
|
.references(() => users.id, { onDelete: 'cascade' }).notNull(),
|
||||||
|
questId: integer('quest_id')
|
||||||
|
.references(() => quests.id, { onDelete: 'cascade' }).notNull(),
|
||||||
|
progress: integer('progress').default(0),
|
||||||
|
completedAt: timestamp('completed_at', { withTimezone: true }),
|
||||||
|
}, (table) => [
|
||||||
|
primaryKey({ columns: [table.userId, table.questId] })
|
||||||
|
]);
|
||||||
|
|
||||||
|
// --- RELATIONS ---
|
||||||
|
export const questsRelations = relations(quests, ({ many }) => ({
|
||||||
|
userEntries: many(userQuests),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const userQuestsRelations = relations(userQuests, ({ one }) => ({
|
||||||
|
user: one(users, {
|
||||||
|
fields: [userQuests.userId],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
quest: one(quests, {
|
||||||
|
fields: [userQuests.questId],
|
||||||
|
references: [quests.id],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
80
shared/db/schema/users.ts
Normal file
80
shared/db/schema/users.ts
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import {
|
||||||
|
pgTable,
|
||||||
|
bigint,
|
||||||
|
varchar,
|
||||||
|
boolean,
|
||||||
|
jsonb,
|
||||||
|
timestamp,
|
||||||
|
integer,
|
||||||
|
primaryKey,
|
||||||
|
index,
|
||||||
|
} from 'drizzle-orm/pg-core';
|
||||||
|
import { relations, type InferSelectModel } from 'drizzle-orm';
|
||||||
|
|
||||||
|
// --- TYPES ---
|
||||||
|
export type Class = InferSelectModel<typeof classes>;
|
||||||
|
export type User = InferSelectModel<typeof users>;
|
||||||
|
export type UserTimer = InferSelectModel<typeof userTimers>;
|
||||||
|
|
||||||
|
// --- TABLES ---
|
||||||
|
export const classes = pgTable('classes', {
|
||||||
|
id: bigint('id', { mode: 'bigint' }).primaryKey(),
|
||||||
|
name: varchar('name', { length: 255 }).unique().notNull(),
|
||||||
|
balance: bigint('balance', { mode: 'bigint' }).default(0n),
|
||||||
|
roleId: varchar('role_id', { length: 255 }),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const users = pgTable('users', {
|
||||||
|
id: bigint('id', { mode: 'bigint' }).primaryKey(),
|
||||||
|
classId: bigint('class_id', { mode: 'bigint' }).references(() => classes.id),
|
||||||
|
username: varchar('username', { length: 255 }).unique().notNull(),
|
||||||
|
isActive: boolean('is_active').default(true),
|
||||||
|
|
||||||
|
// Economy
|
||||||
|
balance: bigint('balance', { mode: 'bigint' }).default(0n),
|
||||||
|
xp: bigint('xp', { mode: 'bigint' }).default(0n),
|
||||||
|
level: integer('level').default(1),
|
||||||
|
dailyStreak: integer('daily_streak').default(0),
|
||||||
|
|
||||||
|
// Metadata
|
||||||
|
settings: jsonb('settings').default({}),
|
||||||
|
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
|
||||||
|
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow(),
|
||||||
|
}, (table) => [
|
||||||
|
index('users_username_idx').on(table.username),
|
||||||
|
index('users_balance_idx').on(table.balance),
|
||||||
|
index('users_level_xp_idx').on(table.level, table.xp),
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const userTimers = pgTable('user_timers', {
|
||||||
|
userId: bigint('user_id', { mode: 'bigint' })
|
||||||
|
.references(() => users.id, { onDelete: 'cascade' }).notNull(),
|
||||||
|
type: varchar('type', { length: 50 }).notNull(), // 'COOLDOWN', 'EFFECT', 'ACCESS'
|
||||||
|
key: varchar('key', { length: 100 }).notNull(), // 'daily', 'chn_12345', 'xp_boost'
|
||||||
|
expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
|
||||||
|
metadata: jsonb('metadata').default({}),
|
||||||
|
}, (table) => [
|
||||||
|
primaryKey({ columns: [table.userId, table.type, table.key] }),
|
||||||
|
index('user_timers_expires_at_idx').on(table.expiresAt),
|
||||||
|
index('user_timers_lookup_idx').on(table.userId, table.type, table.key),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// --- RELATIONS ---
|
||||||
|
export const classesRelations = relations(classes, ({ many }) => ({
|
||||||
|
users: many(users),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const usersRelations = relations(users, ({ one, many }) => ({
|
||||||
|
class: one(classes, {
|
||||||
|
fields: [users.classId],
|
||||||
|
references: [classes.id],
|
||||||
|
}),
|
||||||
|
timers: many(userTimers),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const userTimersRelations = relations(userTimers, ({ one }) => ({
|
||||||
|
user: one(users, {
|
||||||
|
fields: [userTimers.userId],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
@@ -171,7 +171,7 @@ export const inventoryService = {
|
|||||||
const results: any[] = [];
|
const results: any[] = [];
|
||||||
|
|
||||||
// 2. Apply Effects
|
// 2. Apply Effects
|
||||||
const { effectHandlers } = await import("@/modules/inventory/effects/registry");
|
const { effectHandlers } = await import("@/modules/inventory/effect.registry");
|
||||||
|
|
||||||
for (const effect of usageData.effects) {
|
for (const effect of usageData.effects) {
|
||||||
const handler = effectHandlers[effect.type];
|
const handler = effectHandlers[effect.type];
|
||||||
|
|||||||
@@ -1,21 +1,30 @@
|
|||||||
# Aurora Web
|
# Aurora Web API
|
||||||
|
|
||||||
To install dependencies:
|
The web API provides a REST interface and WebSocket support for accessing Aurora bot data and configuration.
|
||||||
|
|
||||||
|
## API Endpoints
|
||||||
|
|
||||||
|
- `GET /api/stats` - Real-time bot statistics
|
||||||
|
- `GET /api/settings` - Bot configuration
|
||||||
|
- `GET /api/users` - User data
|
||||||
|
- `GET /api/items` - Item catalog
|
||||||
|
- `GET /api/quests` - Quest information
|
||||||
|
- `GET /api/transactions` - Economy data
|
||||||
|
- `GET /api/health` - Health check
|
||||||
|
|
||||||
|
## WebSocket
|
||||||
|
|
||||||
|
Connect to `/ws` for real-time updates:
|
||||||
|
- Stats broadcasts every 5 seconds
|
||||||
|
- Event notifications via system bus
|
||||||
|
- PING/PONG heartbeat support
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
The API runs automatically when you start the bot:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bun install
|
bun run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
To start a development server:
|
The API will be available at `http://localhost:3000`
|
||||||
|
|
||||||
```bash
|
|
||||||
bun dev
|
|
||||||
```
|
|
||||||
|
|
||||||
To run for production:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bun start
|
|
||||||
```
|
|
||||||
|
|
||||||
This project was created using `bun init` in bun v1.3.3. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
|
|
||||||
|
|||||||
327
web/bun.lock
327
web/bun.lock
@@ -1,327 +0,0 @@
|
|||||||
{
|
|
||||||
"lockfileVersion": 1,
|
|
||||||
"configVersion": 1,
|
|
||||||
"workspaces": {
|
|
||||||
"": {
|
|
||||||
"name": "bun-react-template",
|
|
||||||
"dependencies": {
|
|
||||||
"@hookform/resolvers": "^5.2.2",
|
|
||||||
"@radix-ui/react-accordion": "^1.2.12",
|
|
||||||
"@radix-ui/react-collapsible": "^1.1.12",
|
|
||||||
"@radix-ui/react-dialog": "^1.1.15",
|
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
||||||
"@radix-ui/react-label": "^2.1.8",
|
|
||||||
"@radix-ui/react-scroll-area": "^1.2.10",
|
|
||||||
"@radix-ui/react-select": "^2.2.6",
|
|
||||||
"@radix-ui/react-separator": "^1.1.8",
|
|
||||||
"@radix-ui/react-slider": "^1.3.6",
|
|
||||||
"@radix-ui/react-slot": "^1.2.4",
|
|
||||||
"@radix-ui/react-switch": "^1.2.6",
|
|
||||||
"@radix-ui/react-tabs": "^1.1.13",
|
|
||||||
"@radix-ui/react-tooltip": "^1.2.8",
|
|
||||||
"bun-plugin-tailwind": "^0.1.2",
|
|
||||||
"class-variance-authority": "^0.7.1",
|
|
||||||
"clsx": "^2.1.1",
|
|
||||||
"lucide-react": "^0.562.0",
|
|
||||||
"next-themes": "^0.4.6",
|
|
||||||
"react": "^19",
|
|
||||||
"react-dom": "^19",
|
|
||||||
"react-easy-crop": "^5.5.6",
|
|
||||||
"react-hook-form": "^7.70.0",
|
|
||||||
"react-router-dom": "^7.12.0",
|
|
||||||
"recharts": "^3.6.0",
|
|
||||||
"sonner": "^2.0.7",
|
|
||||||
"tailwind-merge": "^3.3.1",
|
|
||||||
"zod": "^4.3.5",
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/bun": "latest",
|
|
||||||
"@types/react": "^19",
|
|
||||||
"@types/react-dom": "^19",
|
|
||||||
"tailwindcss": "^4.1.11",
|
|
||||||
"tw-animate-css": "^1.4.0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"packages": {
|
|
||||||
"@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=="],
|
|
||||||
|
|
||||||
"@hookform/resolvers": ["@hookform/resolvers@5.2.2", "", { "dependencies": { "@standard-schema/utils": "^0.3.0" }, "peerDependencies": { "react-hook-form": "^7.55.0" } }, "sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA=="],
|
|
||||||
|
|
||||||
"@oven/bun-darwin-aarch64": ["@oven/bun-darwin-aarch64@1.3.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-8GvNtMo0NINM7Emk9cNAviCG3teEgr3BUX9be0+GD029zIagx2Sf54jMui1Eu1IpFm7nWHODuLEefGOQNaJ0gQ=="],
|
|
||||||
|
|
||||||
"@oven/bun-darwin-x64": ["@oven/bun-darwin-x64@1.3.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-r33eHQOHAwkuiBJIwmkXIyqONQOQMnd1GMTpDzaxx9vf9+svby80LZO9Hcm1ns6KT/TBRFyODC/0loA7FAaffg=="],
|
|
||||||
|
|
||||||
"@oven/bun-darwin-x64-baseline": ["@oven/bun-darwin-x64-baseline@1.3.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-p5q3rJk48qhLuLBOFehVc+kqCE03YrswTc6NCxbwsxiwfySXwcAvpF2KWKF/ZZObvvR8hCCvqe1F81b2p5r2dg=="],
|
|
||||||
|
|
||||||
"@oven/bun-linux-aarch64": ["@oven/bun-linux-aarch64@1.3.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-zkcHPI23QxJ1TdqafhgkXt1NOEN8o5C460sVeNnrhfJ43LwZgtfcvcQE39x/pBedu67fatY8CU0iY00nOh46ZQ=="],
|
|
||||||
|
|
||||||
"@oven/bun-linux-aarch64-musl": ["@oven/bun-linux-aarch64-musl@1.3.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-HKBeUlJdNduRkzJKZ5DXM+pPqntfC50/Hu2X65jVX0Y7hu/6IC8RaUTqpr8FtCZqqmc9wDK0OTL+Mbi9UQIKYQ=="],
|
|
||||||
|
|
||||||
"@oven/bun-linux-x64": ["@oven/bun-linux-x64@1.3.5", "", { "os": "linux", "cpu": "x64" }, "sha512-n7zhKTSDZS0yOYg5Rq8easZu5Y/o47sv0c7yGr2ciFdcie9uYV55fZ7QMqhWMGK33ezCSikh5EDkUMCIvfWpjA=="],
|
|
||||||
|
|
||||||
"@oven/bun-linux-x64-baseline": ["@oven/bun-linux-x64-baseline@1.3.5", "", { "os": "linux", "cpu": "x64" }, "sha512-FeCQyBU62DMuB0nn01vPnf3McXrKOsrK9p7sHaBFYycw0mmoU8kCq/WkBkGMnLuvQljJSyen8QBTx+fXdNupWg=="],
|
|
||||||
|
|
||||||
"@oven/bun-linux-x64-musl": ["@oven/bun-linux-x64-musl@1.3.5", "", { "os": "linux", "cpu": "x64" }, "sha512-XkCCHkByYn8BIDvoxnny898znju4xnW2kvFE8FT5+0Y62cWdcBGMZ9RdsEUTeRz16k8hHtJpaSfLcEmNTFIwRQ=="],
|
|
||||||
|
|
||||||
"@oven/bun-linux-x64-musl-baseline": ["@oven/bun-linux-x64-musl-baseline@1.3.5", "", { "os": "linux", "cpu": "x64" }, "sha512-TJiYC7KCr0XxFTsxgwQOeE7dncrEL/RSyL0EzSL3xRkrxJMWBCvCSjQn7LV1i6T7hFst0+3KoN3VWvD5BinqHA=="],
|
|
||||||
|
|
||||||
"@oven/bun-windows-x64": ["@oven/bun-windows-x64@1.3.5", "", { "os": "win32", "cpu": "x64" }, "sha512-T3xkODItb/0ftQPFsZDc7EAX2D6A4TEazQ2YZyofZToO8Q7y8YT8ooWdhd0BQiTCd66uEvgE1DCZetynwg2IoA=="],
|
|
||||||
|
|
||||||
"@oven/bun-windows-x64-baseline": ["@oven/bun-windows-x64-baseline@1.3.5", "", { "os": "win32", "cpu": "x64" }, "sha512-rtVQB9/1XK8FWJgFtsOthbPifRMYypgJwxu+pK3NHx8WvFKmq7HcPDqNr8xLzGULjQEO7eAo2aOZfONOwYz+5g=="],
|
|
||||||
|
|
||||||
"@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-accordion": ["@radix-ui/react-accordion@1.2.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collapsible": "1.1.12", "@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-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-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA=="],
|
|
||||||
|
|
||||||
"@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-collapsible": ["@radix-ui/react-collapsible@1.1.12", "", { "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-presence": "1.1.5", "@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" }, "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-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA=="],
|
|
||||||
|
|
||||||
"@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.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "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-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A=="],
|
|
||||||
|
|
||||||
"@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.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "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-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g=="],
|
|
||||||
|
|
||||||
"@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.4", "", { "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-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA=="],
|
|
||||||
|
|
||||||
"@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-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@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-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-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="],
|
|
||||||
|
|
||||||
"@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-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=="],
|
|
||||||
|
|
||||||
"@reduxjs/toolkit": ["@reduxjs/toolkit@2.11.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@standard-schema/utils": "^0.3.0", "immer": "^11.0.0", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "optionalPeers": ["react", "react-redux"] }, "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ=="],
|
|
||||||
|
|
||||||
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="],
|
|
||||||
|
|
||||||
"@types/bun": ["@types/bun@1.3.5", "", { "dependencies": { "bun-types": "1.3.5" } }, "sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w=="],
|
|
||||||
|
|
||||||
"@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="],
|
|
||||||
|
|
||||||
"@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="],
|
|
||||||
|
|
||||||
"@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="],
|
|
||||||
|
|
||||||
"@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "*" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="],
|
|
||||||
|
|
||||||
"@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="],
|
|
||||||
|
|
||||||
"@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "*" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="],
|
|
||||||
|
|
||||||
"@types/d3-shape": ["@types/d3-shape@3.1.7", "", { "dependencies": { "@types/d3-path": "*" } }, "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg=="],
|
|
||||||
|
|
||||||
"@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="],
|
|
||||||
|
|
||||||
"@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="],
|
|
||||||
|
|
||||||
"@types/node": ["@types/node@25.0.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA=="],
|
|
||||||
|
|
||||||
"@types/react": ["@types/react@19.2.7", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg=="],
|
|
||||||
|
|
||||||
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
|
|
||||||
|
|
||||||
"@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="],
|
|
||||||
|
|
||||||
"aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="],
|
|
||||||
|
|
||||||
"bun": ["bun@1.3.5", "", { "optionalDependencies": { "@oven/bun-darwin-aarch64": "1.3.5", "@oven/bun-darwin-x64": "1.3.5", "@oven/bun-darwin-x64-baseline": "1.3.5", "@oven/bun-linux-aarch64": "1.3.5", "@oven/bun-linux-aarch64-musl": "1.3.5", "@oven/bun-linux-x64": "1.3.5", "@oven/bun-linux-x64-baseline": "1.3.5", "@oven/bun-linux-x64-musl": "1.3.5", "@oven/bun-linux-x64-musl-baseline": "1.3.5", "@oven/bun-windows-x64": "1.3.5", "@oven/bun-windows-x64-baseline": "1.3.5" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "x64", "arm64", ], "bin": { "bun": "bin/bun.exe", "bunx": "bin/bunx.exe" } }, "sha512-c1YHIGUfgvYPJmLug5QiLzNWlX2Dg7X/67JWu1Va+AmMXNXzC/KQn2lgQ7rD+n1u1UqDpJMowVGGxTNpbPydNw=="],
|
|
||||||
|
|
||||||
"bun-plugin-tailwind": ["bun-plugin-tailwind@0.1.2", "", { "peerDependencies": { "bun": ">=1.0.0" } }, "sha512-41jNC1tZRSK3s1o7pTNrLuQG8kL/0vR/JgiTmZAJ1eHwe0w5j6HFPKeqEk0WAD13jfrUC7+ULuewFBBCoADPpg=="],
|
|
||||||
|
|
||||||
"bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="],
|
|
||||||
|
|
||||||
"class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],
|
|
||||||
|
|
||||||
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
|
|
||||||
|
|
||||||
"cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="],
|
|
||||||
|
|
||||||
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
|
|
||||||
|
|
||||||
"d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="],
|
|
||||||
|
|
||||||
"d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="],
|
|
||||||
|
|
||||||
"d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="],
|
|
||||||
|
|
||||||
"d3-format": ["d3-format@3.1.0", "", {}, "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA=="],
|
|
||||||
|
|
||||||
"d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="],
|
|
||||||
|
|
||||||
"d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="],
|
|
||||||
|
|
||||||
"d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", "d3-interpolate": "1.2.0 - 3", "d3-time": "2.1.1 - 3", "d3-time-format": "2 - 4" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="],
|
|
||||||
|
|
||||||
"d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "^3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="],
|
|
||||||
|
|
||||||
"d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "2 - 3" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="],
|
|
||||||
|
|
||||||
"d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "1 - 3" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="],
|
|
||||||
|
|
||||||
"d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="],
|
|
||||||
|
|
||||||
"decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="],
|
|
||||||
|
|
||||||
"detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="],
|
|
||||||
|
|
||||||
"es-toolkit": ["es-toolkit@1.43.0", "", {}, "sha512-SKCT8AsWvYzBBuUqMk4NPwFlSdqLpJwmy6AP322ERn8W2YLIB6JBXnwMI2Qsh2gfphT3q7EKAxKb23cvFHFwKA=="],
|
|
||||||
|
|
||||||
"eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="],
|
|
||||||
|
|
||||||
"get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="],
|
|
||||||
|
|
||||||
"immer": ["immer@10.2.0", "", {}, "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw=="],
|
|
||||||
|
|
||||||
"internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="],
|
|
||||||
|
|
||||||
"lucide-react": ["lucide-react@0.562.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw=="],
|
|
||||||
|
|
||||||
"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=="],
|
|
||||||
|
|
||||||
"normalize-wheel": ["normalize-wheel@1.0.1", "", {}, "sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA=="],
|
|
||||||
|
|
||||||
"react": ["react@19.2.3", "", {}, "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA=="],
|
|
||||||
|
|
||||||
"react-dom": ["react-dom@19.2.3", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.3" } }, "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg=="],
|
|
||||||
|
|
||||||
"react-easy-crop": ["react-easy-crop@5.5.6", "", { "dependencies": { "normalize-wheel": "^1.0.1", "tslib": "^2.0.1" }, "peerDependencies": { "react": ">=16.4.0", "react-dom": ">=16.4.0" } }, "sha512-Jw3/ozs8uXj3NpL511Suc4AHY+mLRO23rUgipXvNYKqezcFSYHxe4QXibBymkOoY6oOtLVMPO2HNPRHYvMPyTw=="],
|
|
||||||
|
|
||||||
"react-hook-form": ["react-hook-form@7.70.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-COOMajS4FI3Wuwrs3GPpi/Jeef/5W1DRR84Yl5/ShlT3dKVFUfoGiEZ/QE6Uw8P4T2/CLJdcTVYKvWBMQTEpvw=="],
|
|
||||||
|
|
||||||
"react-is": ["react-is@19.2.3", "", {}, "sha512-qJNJfu81ByyabuG7hPFEbXqNcWSU3+eVus+KJs+0ncpGfMyYdvSmxiJxbWR65lYi1I+/0HBcliO029gc4F+PnA=="],
|
|
||||||
|
|
||||||
"react-redux": ["react-redux@9.2.0", "", { "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "@types/react": "^18.2.25 || ^19", "react": "^18.0 || ^19", "redux": "^5.0.0" }, "optionalPeers": ["@types/react", "redux"] }, "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g=="],
|
|
||||||
|
|
||||||
"react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "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-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="],
|
|
||||||
|
|
||||||
"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.12.0", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-kTPDYPFzDVGIIGNLS5VJykK0HfHLY5MF3b+xj0/tTyNYL1gF1qs7u67Z9jEhQk2sQ98SUaHxlG31g1JtF7IfVw=="],
|
|
||||||
|
|
||||||
"react-router-dom": ["react-router-dom@7.12.0", "", { "dependencies": { "react-router": "7.12.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-pfO9fiBcpEfX4Tx+iTYKDtPbrSLLCbwJ5EqP+SPYQu1VYCXdy79GSj0wttR0U4cikVdlImZuEZ/9ZNCgoaxwBA=="],
|
|
||||||
|
|
||||||
"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=="],
|
|
||||||
|
|
||||||
"recharts": ["recharts@3.6.0", "", { "dependencies": { "@reduxjs/toolkit": "1.x.x || 2.x.x", "clsx": "^2.1.1", "decimal.js-light": "^2.5.1", "es-toolkit": "^1.39.3", "eventemitter3": "^5.0.1", "immer": "^10.1.1", "react-redux": "8.x.x || 9.x.x", "reselect": "5.1.1", "tiny-invariant": "^1.3.3", "use-sync-external-store": "^1.2.2", "victory-vendor": "^37.0.2" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-L5bjxvQRAe26RlToBAziKUB7whaGKEwD3znoM6fz3DrTowCIC/FnJYnuq1GEzB8Zv2kdTfaxQfi5GoH0tBinyg=="],
|
|
||||||
|
|
||||||
"redux": ["redux@5.0.1", "", {}, "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="],
|
|
||||||
|
|
||||||
"redux-thunk": ["redux-thunk@3.1.0", "", { "peerDependencies": { "redux": "^5.0.0" } }, "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw=="],
|
|
||||||
|
|
||||||
"reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="],
|
|
||||||
|
|
||||||
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
|
||||||
|
|
||||||
"set-cookie-parser": ["set-cookie-parser@2.7.2", "", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="],
|
|
||||||
|
|
||||||
"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=="],
|
|
||||||
|
|
||||||
"tailwind-merge": ["tailwind-merge@3.4.0", "", {}, "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g=="],
|
|
||||||
|
|
||||||
"tailwindcss": ["tailwindcss@4.1.18", "", {}, "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw=="],
|
|
||||||
|
|
||||||
"tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="],
|
|
||||||
|
|
||||||
"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=="],
|
|
||||||
|
|
||||||
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
|
||||||
|
|
||||||
"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.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
|
|
||||||
|
|
||||||
"victory-vendor": ["victory-vendor@37.3.6", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ=="],
|
|
||||||
|
|
||||||
"zod": ["zod@4.3.5", "", {}, "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g=="],
|
|
||||||
|
|
||||||
"@radix-ui/react-collection/@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-dialog/@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-label/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "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-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
|
|
||||||
|
|
||||||
"@radix-ui/react-menu/@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-primitive/@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-select/@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-separator/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "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-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
|
|
||||||
|
|
||||||
"@radix-ui/react-tooltip/@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=="],
|
|
||||||
|
|
||||||
"@reduxjs/toolkit/immer": ["immer@11.1.3", "", {}, "sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q=="],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "bun-react-template",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"private": true,
|
|
||||||
"type": "module",
|
|
||||||
"scripts": {
|
|
||||||
"dev": "bun --hot src/index.ts",
|
|
||||||
"start": "NODE_ENV=production bun src/index.ts",
|
|
||||||
"build": "bun run build.ts"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@hookform/resolvers": "^5.2.2",
|
|
||||||
"@radix-ui/react-accordion": "^1.2.12",
|
|
||||||
"@radix-ui/react-collapsible": "^1.1.12",
|
|
||||||
"@radix-ui/react-dialog": "^1.1.15",
|
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
||||||
"@radix-ui/react-label": "^2.1.8",
|
|
||||||
"@radix-ui/react-scroll-area": "^1.2.10",
|
|
||||||
"@radix-ui/react-select": "^2.2.6",
|
|
||||||
"@radix-ui/react-separator": "^1.1.8",
|
|
||||||
"@radix-ui/react-slider": "^1.3.6",
|
|
||||||
"@radix-ui/react-slot": "^1.2.4",
|
|
||||||
"@radix-ui/react-switch": "^1.2.6",
|
|
||||||
"@radix-ui/react-tabs": "^1.1.13",
|
|
||||||
"@radix-ui/react-tooltip": "^1.2.8",
|
|
||||||
"bun-plugin-tailwind": "^0.1.2",
|
|
||||||
"class-variance-authority": "^0.7.1",
|
|
||||||
"clsx": "^2.1.1",
|
|
||||||
"lucide-react": "^0.562.0",
|
|
||||||
"next-themes": "^0.4.6",
|
|
||||||
"react": "^19",
|
|
||||||
"react-dom": "^19",
|
|
||||||
"react-easy-crop": "^5.5.6",
|
|
||||||
"react-hook-form": "^7.70.0",
|
|
||||||
"react-router-dom": "^7.12.0",
|
|
||||||
"recharts": "^3.6.0",
|
|
||||||
"sonner": "^2.0.7",
|
|
||||||
"tailwind-merge": "^3.3.1",
|
|
||||||
"zod": "^4.3.5"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/react": "^19",
|
|
||||||
"@types/react-dom": "^19",
|
|
||||||
"@types/bun": "latest",
|
|
||||||
"tailwindcss": "^4.1.11",
|
|
||||||
"tw-animate-css": "^1.4.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +1,10 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
// Environment setup & latest features
|
// Environment setup & latest features
|
||||||
"lib": [
|
"lib": ["ESNext"],
|
||||||
"ESNext",
|
|
||||||
"DOM"
|
|
||||||
],
|
|
||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
"module": "Preserve",
|
"module": "Preserve",
|
||||||
"moduleDetection": "force",
|
"moduleDetection": "force",
|
||||||
"jsx": "react-jsx",
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
// Bundler mode
|
// Bundler mode
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
@@ -38,8 +34,5 @@
|
|||||||
"noUnusedParameters": false,
|
"noUnusedParameters": false,
|
||||||
"noPropertyAccessFromIndexSignature": false
|
"noPropertyAccessFromIndexSignature": false
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": ["node_modules"]
|
||||||
"dist",
|
|
||||||
"node_modules"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user