diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..a431deb
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,18 @@
+GOOGLE_CLIENT_ID="your-google-client-id-here"
+GOOGLE_CLIENT_SECRET="your-google-client-secret-here"
+GOOGLE_LOGIN_DOMAIN="http://localhost:5173"
+DATABASE_URL="postgresql://username:password@localhost:5432/bottlecrm?schema=public"
+
+# API Configuration
+API_PORT=3001
+JWT_SECRET=your-super-secure-jwt-secret-key-change-this-in-production
+JWT_EXPIRES_IN=24h
+FRONTEND_URL=http://localhost:5173
+
+# Logging Configuration
+ENABLE_REQUEST_LOGGING=true
+LOG_REQUEST_BODY=false
+LOG_RESPONSE_BODY=false
+
+# Environment
+NODE_ENV=development
\ No newline at end of file
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..efc6d1b
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,98 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Project Overview
+
+BottleCRM is a SaaS CRM platform built with SvelteKit, designed for startups and enterprises with role-based access control (RBAC). The application features multi-tenancy through organizations, with strict data isolation enforced at the database level.
+
+## Technology Stack
+
+- **Frontend**: SvelteKit 2.x with Svelte 5.x
+- **Styling**: TailwindCSS 4.x
+- **Database**: PostgreSQL with Prisma ORM
+- **Icons**: Lucide Svelte
+- **Validation**: Zod
+- **Package Manager**: pnpm
+
+## Development Commands
+
+```bash
+# Development server
+pnpm run dev
+
+# Build for production
+pnpm run build
+
+# Preview production build
+pnpm run preview
+
+# Type checking
+pnpm run check
+
+# Type checking with watch mode
+pnpm run check:watch
+
+# Linting and formatting (both required to pass)
+pnpm run lint
+
+# Format code
+pnpm run format
+
+# Database operations
+npx prisma migrate dev
+npx prisma generate
+npx prisma studio
+```
+
+## Architecture Overview
+
+### Multi-Tenant Structure
+- **Organizations**: Top-level tenant containers with strict data isolation
+- **Users**: Can belong to multiple organizations with different roles (ADMIN/USER)
+- **Super Admin**: Users with @micropyramid.com email domain have platform-wide access
+
+### Core CRM Entities
+- **Leads**: Initial prospects that can be converted to Accounts/Contacts/Opportunities
+- **Accounts**: Company/organization records
+- **Contacts**: Individual people associated with accounts
+- **Opportunities**: Sales deals with pipeline stages
+- **Tasks/Events**: Activity management
+- **Cases**: Customer support tickets
+- **Products/Quotes**: Sales catalog and quotation system
+
+### Authentication & Authorization
+- Session-based authentication using cookies (`session`, `org`, `org_name`)
+- Organization selection required after login via `/org` route
+- Route protection in `src/hooks.server.js`:
+ - `/app/*` routes require authentication and organization membership
+ - `/admin/*` routes restricted to @micropyramid.com domain users
+ - `/org` route for organization selection
+
+### Data Access Control
+- All database queries must include organization filtering
+- User can only access data from organizations they belong to
+- Prisma schema enforces relationships with `organizationId` foreign keys
+
+### Route Structure
+- `(site)`: Public marketing pages
+- `(no-layout)`: Auth pages (login, org selection)
+- `(app)`: Main CRM application (requires auth + org membership)
+- `(admin)`: Platform administration (requires @micropyramid.com email)
+
+### Key Files
+- `src/hooks.server.js`: Authentication, org membership validation, route protection
+- `src/lib/prisma.js`: Database client configuration
+- `src/lib/stores/auth.js`: Authentication state management
+- `prisma/schema.prisma`: Complete database schema with RBAC models
+
+## Form Development
+- All form labels must be properly associated with form controls for accessibility
+- Use Zod for form validation
+- Follow existing patterns in `/contacts`, `/leads`, `/accounts` for consistency
+
+## Security Requirements
+- Never expose cross-organization data
+- Always filter queries by user's organization membership
+- Validate user permissions before any data operations
+- Use parameterized queries via Prisma to prevent SQL injection
\ No newline at end of file
diff --git a/ENV.md b/ENV.md
deleted file mode 100644
index 64ef0b2..0000000
--- a/ENV.md
+++ /dev/null
@@ -1,4 +0,0 @@
-GOOGLE_CLIENT_ID=""
-GOOGLE_CLIENT_SECRET=""
-GOOGLE_LOGIN_DOMAIN="http://localhost:5173"
-DATABASE_URL="postgresql://postgres:root@localhost:5432/bottlecrm?schema=public"
\ No newline at end of file
diff --git a/README.md b/README.md
index a597ffe..aaa9674 100644
--- a/README.md
+++ b/README.md
@@ -1,79 +1,205 @@
# BottleCRM: Free and Open Source Customer Relationship Management
-
Powerful, Modern CRM for Everyone
+ Powerful, Modern Multi-Tenant CRM for Everyone
-BottleCRM is a free, open-source Customer Relationship Management solution designed to help small and medium businesses effectively manage their customer relationships. Built with modern technologies, it offers a comprehensive set of features without the enterprise price tag.
+BottleCRM is a free, open-source Customer Relationship Management solution designed to help small and medium businesses effectively manage their customer relationships. Built with modern technologies and enterprise-grade multi-tenancy, it offers a comprehensive set of features without the enterprise price tag.
-## 🚀 Features
+## ✨ Key Highlights
+- **Multi-Tenant Architecture**: Secure organization-based data isolation
+- **Role-Based Access Control**: Granular permissions for users and admins
+- **Modern Technology Stack**: Built with SvelteKit 2.x, Svelte 5.x, and PostgreSQL
+- **Mobile-First Design**: Responsive interface optimized for all devices
+
+## 🚀 Core Features
+
+### Sales & Lead Management
- **Lead Management**: Track and nurture leads from initial contact to conversion
- **Account Management**: Maintain detailed records of customer accounts and organizations
- **Contact Management**: Store and organize all your customer contact information
+- **Opportunity Management**: Track deals through your sales pipeline with customizable stages
+
+### Customer Support
- **Case Management**: Handle customer support cases and track resolution
+- **Solution Knowledge Base**: Maintain searchable solutions for common issues
+- **Multi-Channel Support**: Handle cases from various origins (email, web, phone)
+
+### Productivity & Collaboration
- **Task Management**: Never miss a follow-up with built-in task tracking
-- **Opportunity Management**: Track deals through your sales pipeline
-- **Mobile Friendly**: Access your CRM data on any device
-- **Modern UI**: Clean, intuitive interface built with Svelte and TailwindCSS
+- **Event Management**: Schedule and manage meetings and activities
+- **Board Management**: Trello-like kanban boards for project tracking
+- **Comment System**: Collaborate with team members on records
+
+### Sales Tools
+- **Quote Management**: Generate professional quotes with line items
+- **Product Catalog**: Maintain product inventory with pricing
+- **Sales Pipeline**: Visual opportunity tracking with probability scoring
+
+### Administrative Features
+- **User Management**: Add team members with appropriate role assignments
+- **Organization Management**: Multi-tenant structure with data isolation
+- **Audit Logging**: Complete activity tracking for compliance
+- **Super Admin Panel**: Platform-wide management for system administrators
## 🔮 Coming Soon
- **Invoice Management**: Create, send, and track invoices (in development)
- **Email Integration**: Connect your email accounts for seamless communication
- **Analytics Dashboard**: Make data-driven decisions with powerful reporting tools
+- **API Integration**: REST API for third-party integrations
-## 🖥️ Technologies
+## 🖥️ Technology Stack
-- **Frontend**: SvelteKit, Flowbite-Svelte, TailwindCSS
-- **Backend**: Prisma ORM with your choice of database
-- **Authentication**: Built-in authentication system
+- **Frontend**: SvelteKit 2.x, Svelte 5.x, TailwindCSS 4.x
+- **Backend**: Node.js with Prisma ORM
+- **Database**: PostgreSQL (recommended) with multi-tenant schema
+- **Authentication**: Session-based authentication with organization membership
+- **Icons**: Lucide Svelte icon library
+- **Validation**: Zod for type-safe form validation
## 🚀 Getting Started
### Prerequisites
-- Node.js (v20 or newer)
-- npm, pnpm, or yarn package manager
-- A database (PostgreSQL recommended)
+- **Node.js**: v22.13.0 (use nvm for version management)
+- **Package Manager**: pnpm (recommended)
+- **Database**: PostgreSQL (required for multi-tenancy features)
### Installation
-1. Clone the repository:
+1. **Clone the repository:**
```bash
git clone https://github.com/micropyramid/svelte-crm.git
cd svelte-crm
```
-2. Install dependencies:
+2. **Set up Node.js version:**
+```bash
+nvm use 22.13.0
+```
+
+3. **Install dependencies:**
```bash
pnpm install
```
-3. Configure your environment variables (see `.env.example`)
+4. **Configure environment variables:**
+Create a `.env` file based on the following template:
+```env
+# Database Configuration
+DATABASE_URL="postgresql://postgres:password@localhost:5432/bottlecrm?schema=public"
-4. Run database migrations:
+# Google OAuth (Optional)
+GOOGLE_CLIENT_ID=""
+GOOGLE_CLIENT_SECRET=""
+GOOGLE_LOGIN_DOMAIN="http://localhost:5173"
+```
+
+5. **Set up the database:**
```bash
+# Generate Prisma client
+npx prisma generate
+
+# Run database migrations
npx prisma migrate dev
+
+# (Optional) Open Prisma Studio to view data
+npx prisma studio
```
-5. Start the development server:
+6. **Start the development server:**
```bash
pnpm run dev
```
+### Development Workflow
+
+Before committing code, ensure quality checks pass:
+
+```bash
+# Type checking
+pnpm run check
+
+# Linting and formatting
+pnpm run lint
+
+# Build verification
+pnpm run build
+```
+
+### Production Deployment
+
+```bash
+# Set Node.js version
+nvm use 22.13.0
+
+# Generate Prisma client
+npx prisma generate
+
+# Run production migrations
+npx prisma migrate deploy
+
+# Build application
+pnpm run build
+
+# Start production server
+pnpm run preview
+```
+
+## 🏗️ Architecture & Security
+
+### Multi-Tenant Design
+- **Organization Isolation**: Complete data separation between organizations
+- **Role-Based Access**: Users can have different roles across organizations
+- **Session Management**: Secure cookie-based authentication with organization context
+
+### User Roles
+- **User**: Standard access to organization data
+- **Admin**: Organization-level administrative privileges
+- **Super Admin**: Platform-wide access (requires @micropyramid.com email)
+
+### Data Security
+- All database queries are organization-scoped
+- Strict permission validation on all routes
+- Audit logging for compliance and tracking
+
+## 📁 Project Structure
+
+```
+src/
+├── routes/
+│ ├── (site)/ # Public marketing pages
+│ ├── (no-layout)/ # Authentication pages
+│ ├── (app)/ # Main CRM application
+│ └── (admin)/ # Super admin panel
+├── lib/
+│ ├── stores/ # Svelte stores for state management
+│ ├── data/ # Static data and configurations
+│ └── utils/ # Utility functions
+└── hooks.server.js # Authentication and route protection
+```
+
## 💬 Community and Feedback
We love to hear from our users! Please share your feedback, report bugs, or suggest new features:
-- Open an issue on GitHub
-- Join our community forum
-- Contribute code via pull requests
+- **Issues**: Open an issue on GitHub for bugs and feature requests
+- **Discussions**: Join community discussions for general questions
+- **Pull Requests**: Contribute code improvements and new features
## 🤝 Contributing
We welcome contributions of all kinds! See our [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to get started.
+### Development Guidelines
+- Follow existing code patterns and conventions
+- Ensure all forms have proper accessibility (labels associated with controls)
+- Never use `$app` imports from SvelteKit (see packaging best practices)
+- Always filter database queries by organization membership
+- Add appropriate error handling and validation
+
## 📄 License
BottleCRM is open source software [licensed as MIT](LICENSE).
diff --git a/api/README.md b/api/README.md
new file mode 100644
index 0000000..74e4fce
--- /dev/null
+++ b/api/README.md
@@ -0,0 +1,137 @@
+# BottleCRM API
+
+Express.js API for BottleCRM with JWT authentication, Swagger documentation, and configurable request logging.
+
+## Features
+
+- **Google OAuth Authentication**: Secure Google Sign-In for mobile apps
+- **Multi-tenant**: Organization-based data isolation using existing Prisma schema
+- **Swagger Documentation**: Interactive API documentation at `/api-docs`
+- **Request Logging**: Configurable input/output HTTP request logging
+- **Security**: Helmet, CORS, rate limiting
+- **Organization Access Control**: Ensures users can only access their organization's data
+
+## Quick Start
+
+1. The required environment variables are already added to your existing `.env` file.
+
+2. **Generate a secure JWT secret** (required for production):
+```bash
+# Using Node.js
+node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
+
+# Using OpenSSL (if available)
+openssl rand -hex 32
+
+# Using online generator (for development only)
+# Visit: https://generate-secret.vercel.app/32
+```
+
+3. Update your `.env` file with the generated secret:
+```env
+JWT_SECRET=your-generated-secret-key-here
+```
+
+4. Start the API server:
+```bash
+# Development with auto-reload
+pnpm run api:dev
+
+# Production
+pnpm run api:start
+```
+
+5. Visit Swagger documentation:
+```
+http://localhost:3001/api-docs
+```
+
+## Authentication
+
+1. **Google Login**: POST `/api/auth/google`
+ - Request: `{ "idToken": "google-id-token-from-mobile-app" }`
+ - Response: `{ "token": "jwt-token", "user": {...} }`
+
+2. **Use Token**: Include in Authorization header:
+ ```
+ Authorization: Bearer
+ ```
+
+3. **Select Organization**: Include organization ID in header:
+ ```
+ X-Organization-ID:
+ ```
+
+## API Endpoints
+
+### Authentication
+- `POST /api/auth/google` - Google OAuth mobile login
+- `GET /api/auth/me` - Get current user profile
+
+### Leads
+- `GET /api/leads` - Get organization leads (paginated)
+- `GET /api/leads/:id` - Get lead by ID
+- `POST /api/leads` - Create new lead
+
+### Accounts
+- `GET /api/accounts` - Get organization accounts
+- `POST /api/accounts` - Create new account
+
+### Contacts
+- `GET /api/contacts` - Get organization contacts
+- `POST /api/contacts` - Create new contact
+
+### Opportunities
+- `GET /api/opportunities` - Get organization opportunities
+- `POST /api/opportunities` - Create new opportunity
+
+## Configuration
+
+### Environment Variables
+
+- `API_PORT`: Server port (default: 3001)
+- `JWT_SECRET`: Secret key for JWT tokens (required) - **Generate using the commands above**
+- `JWT_EXPIRES_IN`: Token expiration time (default: 24h)
+- `FRONTEND_URL`: Frontend URL for CORS (default: http://localhost:5173)
+
+### Logging Configuration
+
+- `LOG_LEVEL`: Logging level (info, debug, error)
+- `ENABLE_REQUEST_LOGGING`: Enable/disable request logging (true/false)
+- `LOG_REQUEST_BODY`: Log request bodies (true/false)
+- `LOG_RESPONSE_BODY`: Log response bodies (true/false)
+
+### Security Features
+
+- **Rate Limiting**: 100 requests per 15 minutes per IP
+- **Helmet**: Security headers
+- **CORS**: Cross-origin request handling
+- **JWT Validation**: Token verification on protected routes
+- **Organization Isolation**: Users can only access their organization's data
+
+## Data Access Control
+
+All API endpoints enforce organization-based access control:
+
+1. **Authentication Required**: All endpoints (except login) require valid JWT token
+2. **Organization Header**: Protected endpoints require `X-Organization-ID` header
+3. **Membership Validation**: User must be a member of the specified organization
+4. **Data Filtering**: All database queries are filtered by organization ID
+
+## Development
+
+The API uses the same Prisma schema as the main SvelteKit application, ensuring data consistency and leveraging existing:
+
+- Database models and relationships
+- Organization-based multi-tenancy
+- User role management (ADMIN/USER)
+- Super admin access (@micropyramid.com domain)
+
+## Testing with Swagger
+
+Access the interactive API documentation at `http://localhost:3001/api-docs` to:
+
+1. Test authentication endpoints
+2. Explore available endpoints
+3. Test API calls with different parameters
+4. View request/response schemas
\ No newline at end of file
diff --git a/api/config/logger.js b/api/config/logger.js
new file mode 100644
index 0000000..fed578c
--- /dev/null
+++ b/api/config/logger.js
@@ -0,0 +1,22 @@
+export const createLogger = () => {
+ return {
+ info: (message, meta) => {
+ console.log(`[INFO] ${message}`);
+ if (meta) {
+ console.log(JSON.stringify(meta, null, 2));
+ }
+ },
+ error: (message, meta) => {
+ console.error(`[ERROR] ${message}`);
+ if (meta) {
+ console.error(JSON.stringify(meta, null, 2));
+ }
+ },
+ warn: (message, meta) => {
+ console.warn(`[WARN] ${message}`);
+ if (meta) {
+ console.warn(JSON.stringify(meta, null, 2));
+ }
+ }
+ };
+};
\ No newline at end of file
diff --git a/api/middleware/auth.js b/api/middleware/auth.js
new file mode 100644
index 0000000..fd84259
--- /dev/null
+++ b/api/middleware/auth.js
@@ -0,0 +1,115 @@
+import jwt from 'jsonwebtoken';
+import { PrismaClient } from '@prisma/client';
+
+const prisma = new PrismaClient();
+
+export const verifyToken = async (req, res, next) => {
+ try {
+ const token = req.header('Authorization')?.replace('Bearer ', '');
+
+ if (!token) {
+ return res.status(401).json({ error: 'Access denied. No token provided.' });
+ }
+
+ // First verify JWT signature and decode
+ const decoded = jwt.verify(token, process.env.JWT_SECRET);
+
+ // Check if token exists in database and is not revoked
+ const dbToken = await prisma.jwtToken.findUnique({
+ where: { token },
+ include: {
+ user: {
+ include: {
+ organizations: {
+ include: {
+ organization: true
+ }
+ }
+ }
+ }
+ }
+ });
+
+ if (!dbToken) {
+ return res.status(401).json({ error: 'Invalid token. Token not found.' });
+ }
+
+ if (dbToken.isRevoked) {
+ return res.status(401).json({ error: 'Token has been revoked.' });
+ }
+
+ if (dbToken.expiresAt < new Date()) {
+ // Mark token as expired in database
+ await prisma.jwtToken.update({
+ where: { id: dbToken.id },
+ data: { isRevoked: true }
+ });
+ return res.status(401).json({ error: 'Token has expired.' });
+ }
+
+ if (!dbToken.user) {
+ return res.status(401).json({ error: 'Invalid token. User not found.' });
+ }
+
+ // Update last used timestamp
+ await prisma.jwtToken.update({
+ where: { id: dbToken.id },
+ data: { lastUsedAt: new Date() }
+ });
+
+ req.user = dbToken.user;
+ req.userId = dbToken.user.id;
+ req.tokenId = dbToken.id;
+ next();
+ } catch (error) {
+ if (error.name === 'JsonWebTokenError') {
+ return res.status(401).json({ error: 'Invalid token format.' });
+ }
+ if (error.name === 'TokenExpiredError') {
+ return res.status(401).json({ error: 'Token has expired.' });
+ }
+ console.error('Token verification error:', error);
+ return res.status(401).json({ error: 'Token validation failed.' });
+ }
+};
+
+export const requireOrganization = async (req, res, next) => {
+ try {
+ const organizationId = req.header('X-Organization-ID');
+
+ if (!organizationId) {
+ return res.status(400).json({ error: 'Organization ID is required in X-Organization-ID header.' });
+ }
+
+ const userOrg = req.user.organizations.find(
+ uo => uo.organizationId === organizationId
+ );
+
+ if (!userOrg) {
+ return res.status(403).json({ error: 'Access denied to this organization.' });
+ }
+
+ req.organizationId = organizationId;
+ req.userRole = userOrg.role;
+ req.organization = userOrg.organization;
+ next();
+ } catch (error) {
+ return res.status(500).json({ error: 'Internal server error.' });
+ }
+};
+
+export const requireRole = (roles) => {
+ return (req, res, next) => {
+ if (!roles.includes(req.userRole)) {
+ return res.status(403).json({ error: 'Insufficient permissions.' });
+ }
+ next();
+ };
+};
+
+export const requireSuperAdmin = (req, res, next) => {
+ if (!req.user.email.endsWith('@micropyramid.com')) {
+ return res.status(403).json({ error: 'Super admin access required.' });
+ }
+ next();
+};
\ No newline at end of file
diff --git a/api/middleware/errorHandler.js b/api/middleware/errorHandler.js
new file mode 100644
index 0000000..b8af078
--- /dev/null
+++ b/api/middleware/errorHandler.js
@@ -0,0 +1,24 @@
+import { createLogger } from '../config/logger.js';
+
+const logger = createLogger();
+
+export const errorHandler = (err, req, res, next) => {
+ logger.error('Unhandled Error', {
+ error: err.message,
+ stack: err.stack,
+ method: req.method,
+ url: req.url,
+ userId: req.user?.id,
+ organizationId: req.organizationId,
+ timestamp: new Date().toISOString(),
+ });
+
+ if (process.env.NODE_ENV === 'production') {
+ res.status(500).json({ error: 'Internal server error' });
+ } else {
+ res.status(500).json({
+ error: err.message,
+ stack: err.stack
+ });
+ }
+};
\ No newline at end of file
diff --git a/api/middleware/requestLogger.js b/api/middleware/requestLogger.js
new file mode 100644
index 0000000..d6989d8
--- /dev/null
+++ b/api/middleware/requestLogger.js
@@ -0,0 +1,76 @@
+export const requestLogger = (req, res, next) => {
+ const start = Date.now();
+
+ const originalSend = res.send;
+ const originalJson = res.json;
+
+ let responseBody = null;
+ let requestBody = null;
+
+ if (req.body && Object.keys(req.body).length > 0) {
+ requestBody = { ...req.body };
+ if (requestBody.password) requestBody.password = '[REDACTED]';
+ if (requestBody.token) requestBody.token = '[REDACTED]';
+ }
+
+ res.send = function(body) {
+ responseBody = body;
+ return originalSend.call(this, body);
+ };
+
+ res.json = function(body) {
+ responseBody = body;
+ return originalJson.call(this, body);
+ };
+
+ res.on('finish', () => {
+ const duration = Date.now() - start;
+
+ const logData = {
+ method: req.method,
+ url: req.url,
+ statusCode: res.statusCode,
+ duration: `${duration}ms`,
+ userAgent: req.get('User-Agent'),
+ ip: req.ip,
+ timestamp: new Date().toISOString(),
+ };
+
+ if (process.env.LOG_REQUEST_BODY === 'true' && requestBody) {
+ logData.requestBody = requestBody;
+ }
+
+ if (process.env.LOG_RESPONSE_BODY === 'true' && responseBody) {
+ try {
+ logData.responseBody = typeof responseBody === 'string' ? JSON.parse(responseBody) : responseBody;
+ } catch (e) {
+ logData.responseBody = responseBody;
+ }
+ }
+
+ if (req.user) {
+ logData.userId = req.user.id;
+ logData.userEmail = req.user.email;
+ }
+
+ if (req.organizationId) {
+ logData.organizationId = req.organizationId;
+ }
+
+ console.log(`\n=== HTTP REQUEST LOG ===`);
+ console.log(`${req.method} ${req.url} - ${res.statusCode} - ${duration}ms`);
+
+ if (requestBody) {
+ console.log('REQUEST BODY:', JSON.stringify(requestBody, null, 2));
+ }
+
+ if (responseBody) {
+ console.log('RESPONSE BODY:', JSON.stringify(responseBody, null, 2));
+ }
+
+ console.log('FULL LOG DATA:', JSON.stringify(logData, null, 2));
+ console.log(`=== END LOG ===\n`);
+ });
+
+ next();
+};
\ No newline at end of file
diff --git a/api/routes/accounts.js b/api/routes/accounts.js
new file mode 100644
index 0000000..6d8f385
--- /dev/null
+++ b/api/routes/accounts.js
@@ -0,0 +1,137 @@
+import express from 'express';
+import { PrismaClient } from '@prisma/client';
+import { verifyToken, requireOrganization } from '../middleware/auth.js';
+
+const router = express.Router();
+const prisma = new PrismaClient();
+
+router.use(verifyToken);
+router.use(requireOrganization);
+
+/**
+ * @swagger
+ * components:
+ * schemas:
+ * Account:
+ * type: object
+ * properties:
+ * id:
+ * type: string
+ * name:
+ * type: string
+ * industry:
+ * type: string
+ * phone:
+ * type: string
+ * email:
+ * type: string
+ * website:
+ * type: string
+ * createdAt:
+ * type: string
+ * format: date-time
+ */
+
+/**
+ * @swagger
+ * /accounts:
+ * get:
+ * summary: Get all accounts for organization
+ * tags: [Accounts]
+ * parameters:
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * responses:
+ * 200:
+ * description: List of accounts
+ */
+router.get('/', async (req, res) => {
+ try {
+ const accounts = await prisma.account.findMany({
+ where: { organizationId: req.organizationId },
+ orderBy: { createdAt: 'desc' },
+ include: {
+ owner: {
+ select: { id: true, firstName: true, lastName: true, email: true }
+ }
+ }
+ });
+
+ res.json({ accounts });
+ } catch (error) {
+ console.error('Get accounts error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+/**
+ * @swagger
+ * /accounts:
+ * post:
+ * summary: Create a new account
+ * tags: [Accounts]
+ * parameters:
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * requestBody:
+ * required: true
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * required:
+ * - name
+ * properties:
+ * name:
+ * type: string
+ * industry:
+ * type: string
+ * phone:
+ * type: string
+ * email:
+ * type: string
+ * website:
+ * type: string
+ * responses:
+ * 201:
+ * description: Account created successfully
+ */
+router.post('/', async (req, res) => {
+ try {
+ const { name, industry, phone, email, website } = req.body;
+
+ if (!name) {
+ return res.status(400).json({ error: 'Account name is required' });
+ }
+
+ const account = await prisma.account.create({
+ data: {
+ name,
+ industry,
+ phone,
+ email,
+ website,
+ organizationId: req.organizationId,
+ ownerId: req.userId
+ },
+ include: {
+ owner: {
+ select: { id: true, firstName: true, lastName: true, email: true }
+ }
+ }
+ });
+
+ res.status(201).json(account);
+ } catch (error) {
+ console.error('Create account error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+export default router;
\ No newline at end of file
diff --git a/api/routes/auth.js b/api/routes/auth.js
new file mode 100644
index 0000000..10cf93a
--- /dev/null
+++ b/api/routes/auth.js
@@ -0,0 +1,323 @@
+import express from 'express';
+import jwt from 'jsonwebtoken';
+import { OAuth2Client } from 'google-auth-library';
+import { PrismaClient } from '@prisma/client';
+import { verifyToken } from '../middleware/auth.js';
+
+const router = express.Router();
+const prisma = new PrismaClient();
+const googleClient = new OAuth2Client(process.env.GOOGLE_CLIENT_ID);
+
+/**
+ * @swagger
+ * components:
+ * schemas:
+ * GoogleLoginRequest:
+ * type: object
+ * required:
+ * - idToken
+ * properties:
+ * idToken:
+ * type: string
+ * description: Google ID token from mobile app
+ * LoginResponse:
+ * type: object
+ * properties:
+ * token:
+ * type: string
+ * user:
+ * type: object
+ * properties:
+ * id:
+ * type: string
+ * email:
+ * type: string
+ * firstName:
+ * type: string
+ * lastName:
+ * type: string
+ * profileImage:
+ * type: string
+ * organizations:
+ * type: array
+ * items:
+ * type: object
+ * properties:
+ * id:
+ * type: string
+ * name:
+ * type: string
+ * role:
+ * type: string
+ */
+
+
+/**
+ * @swagger
+ * /auth/me:
+ * get:
+ * summary: Get current user profile
+ * tags: [Authentication]
+ * responses:
+ * 200:
+ * description: User profile
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * properties:
+ * user:
+ * type: object
+ * properties:
+ * id:
+ * type: string
+ * email:
+ * type: string
+ * firstName:
+ * type: string
+ * lastName:
+ * type: string
+ * organizations:
+ * type: array
+ * 401:
+ * description: Unauthorized
+ */
+router.get('/me', verifyToken, async (req, res) => {
+ try {
+ const userResponse = {
+ id: req.user.id,
+ email: req.user.email,
+ firstName: req.user.firstName,
+ lastName: req.user.lastName,
+ organizations: req.user.userOrganizations.map(uo => ({
+ id: uo.organization.id,
+ name: uo.organization.name,
+ role: uo.role
+ }))
+ };
+
+ res.json({ user: userResponse });
+ } catch (error) {
+ console.error('Profile error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+/**
+ * @swagger
+ * /auth/google:
+ * post:
+ * summary: Google OAuth mobile login
+ * tags: [Authentication]
+ * security: []
+ * requestBody:
+ * required: true
+ * content:
+ * application/json:
+ * schema:
+ * $ref: '#/components/schemas/GoogleLoginRequest'
+ * responses:
+ * 200:
+ * description: Login successful
+ * content:
+ * application/json:
+ * schema:
+ * $ref: '#/components/schemas/LoginResponse'
+ * 400:
+ * description: Invalid Google token or user not found
+ * 500:
+ * description: Server error
+ */
+router.post('/google', async (req, res) => {
+ try {
+ const { idToken } = req.body;
+
+ if (!idToken) {
+ return res.status(400).json({ error: 'Google ID token is required' });
+ }
+
+ // Support both web and mobile client IDs
+ const audiences = [
+ process.env.GOOGLE_CLIENT_ID
+ ];
+
+ const ticket = await googleClient.verifyIdToken({
+ idToken,
+ audience: audiences
+ });
+
+ const payload = ticket.getPayload();
+
+ if (!payload || !payload.email) {
+ return res.status(400).json({ error: 'Invalid Google token' });
+ }
+
+ let user = await prisma.user.upsert({
+ where: { email: payload.email },
+ update: {
+ profilePhoto: payload.picture,
+ lastLogin: new Date(),
+ // Update name fields if they exist in the token
+ ...(payload.name && { name: payload.name })
+ },
+ create: {
+ email: payload.email,
+ name: payload.name || `${payload.given_name || ''} ${payload.family_name || ''}`.trim(),
+ profilePhoto: payload.picture,
+ user_id: payload.sub, // Use 'sub' field which is the stable Google user ID
+ lastLogin: new Date()
+ },
+ include: {
+ organizations: {
+ include: {
+ organization: true
+ }
+ }
+ }
+ });
+
+ // Create JWT token for API access
+ const JWTtoken = jwt.sign(
+ { userId: user.id },
+ process.env.JWT_SECRET,
+ { expiresIn: process.env.JWT_EXPIRES_IN || '24h' }
+ );
+
+ // Calculate expiration date
+ const expiresIn = process.env.JWT_EXPIRES_IN || '24h';
+ const expirationHours = expiresIn.includes('h') ? parseInt(expiresIn) : 24;
+ const expiresAt = new Date(Date.now() + expirationHours * 60 * 60 * 1000);
+
+ // Store JWT token in database
+ await prisma.jwtToken.create({
+ data: {
+ token: JWTtoken,
+ userId: user.id,
+ expiresAt: expiresAt,
+ deviceInfo: req.get('User-Agent'),
+ ipAddress: req.ip || req.socket.remoteAddress
+ }
+ });
+
+ // Format response to match SvelteKit patterns
+ const userResponse = {
+ id: user.id,
+ email: user.email,
+ name: user.name,
+ profileImage: user.profilePhoto,
+ };
+
+ res.json({
+ success: true,
+ JWTtoken,
+ user: userResponse,
+ organizations: user.organizations.map(uo => ({
+ id: uo.organization.id,
+ name: uo.organization.name,
+ role: uo.role
+ }))
+ });
+ } catch (error) {
+ console.error('Google login error:', error);
+ if (error.message && error.message.includes('Invalid token')) {
+ return res.status(400).json({ error: 'Invalid Google token' });
+ }
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+/**
+ * @swagger
+ * /auth/logout:
+ * post:
+ * summary: Logout and revoke current JWT token
+ * tags: [Authentication]
+ * security:
+ * - bearerAuth: []
+ * responses:
+ * 200:
+ * description: Successfully logged out
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * properties:
+ * success:
+ * type: boolean
+ * message:
+ * type: string
+ * 401:
+ * description: Unauthorized
+ */
+router.post('/logout', verifyToken, async (req, res) => {
+ try {
+ // Revoke the current token
+ await prisma.jwtToken.update({
+ where: { id: req.tokenId },
+ data: {
+ isRevoked: true,
+ updatedAt: new Date()
+ }
+ });
+
+ res.json({
+ success: true,
+ message: 'Successfully logged out'
+ });
+ } catch (error) {
+ console.error('Logout error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+/**
+ * @swagger
+ * /auth/revoke-all:
+ * post:
+ * summary: Revoke all JWT tokens for current user
+ * tags: [Authentication]
+ * security:
+ * - bearerAuth: []
+ * responses:
+ * 200:
+ * description: Successfully revoked all tokens
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * properties:
+ * success:
+ * type: boolean
+ * message:
+ * type: string
+ * revokedCount:
+ * type: integer
+ * 401:
+ * description: Unauthorized
+ */
+router.post('/revoke-all', verifyToken, async (req, res) => {
+ try {
+ // Revoke all tokens for the user
+ const result = await prisma.jwtToken.updateMany({
+ where: {
+ userId: req.userId,
+ isRevoked: false
+ },
+ data: {
+ isRevoked: true,
+ updatedAt: new Date()
+ }
+ });
+
+ res.json({
+ success: true,
+ message: 'Successfully revoked all tokens',
+ revokedCount: result.count
+ });
+ } catch (error) {
+ console.error('Revoke all tokens error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+export default router;
\ No newline at end of file
diff --git a/api/routes/contacts.js b/api/routes/contacts.js
new file mode 100644
index 0000000..7d78f0f
--- /dev/null
+++ b/api/routes/contacts.js
@@ -0,0 +1,261 @@
+import express from 'express';
+import { PrismaClient } from '@prisma/client';
+import { verifyToken, requireOrganization } from '../middleware/auth.js';
+
+const router = express.Router();
+const prisma = new PrismaClient();
+
+router.use(verifyToken);
+router.use(requireOrganization);
+
+/**
+ * @swagger
+ * /contacts:
+ * get:
+ * summary: Get all contacts for organization
+ * tags: [Contacts]
+ * parameters:
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * responses:
+ * 200:
+ * description: List of contacts
+ */
+router.get('/', async (req, res) => {
+ try {
+ const contacts = await prisma.contact.findMany({
+ where: { organizationId: req.organizationId },
+ orderBy: { createdAt: 'desc' },
+ include: {
+ relatedAccounts: {
+ include: {
+ account: {
+ select: { id: true, name: true }
+ }
+ }
+ },
+ owner: {
+ select: { id: true, name: true, email: true }
+ }
+ }
+ });
+
+ res.json({ contacts });
+ } catch (error) {
+ console.error('Get contacts error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+/**
+ * @swagger
+ * /contacts:
+ * post:
+ * summary: Create a new contact
+ * tags: [Contacts]
+ * parameters:
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * requestBody:
+ * required: true
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * required:
+ * - firstName
+ * - lastName
+ * properties:
+ * firstName:
+ * type: string
+ * lastName:
+ * type: string
+ * email:
+ * type: string
+ * phone:
+ * type: string
+ * title:
+ * type: string
+ * department:
+ * type: string
+ * street:
+ * type: string
+ * city:
+ * type: string
+ * state:
+ * type: string
+ * postalCode:
+ * type: string
+ * country:
+ * type: string
+ * description:
+ * type: string
+ * accountId:
+ * type: string
+ * description: UUID of the account to associate with this contact
+ * responses:
+ * 201:
+ * description: Contact created successfully
+ * 400:
+ * description: Validation error
+ */
+router.post('/', async (req, res) => {
+ try {
+ const { firstName, lastName, email, phone, title, department, street, city, state, postalCode, country, description, accountId } = req.body;
+
+ if (!firstName || !lastName) {
+ return res.status(400).json({ error: 'First name and last name are required' });
+ }
+
+ // Validate account if provided
+ let account = null;
+ if (accountId) {
+ account = await prisma.account.findFirst({
+ where: {
+ id: accountId,
+ organizationId: req.organizationId
+ }
+ });
+
+ if (!account) {
+ return res.status(400).json({ error: 'Account not found in your organization' });
+ }
+ }
+
+ // Check for duplicate email within the organization if email is provided
+ if (email) {
+ const existingContact = await prisma.contact.findFirst({
+ where: {
+ email: email,
+ organizationId: req.organizationId
+ }
+ });
+
+ if (existingContact) {
+ return res.status(400).json({ error: 'A contact with this email already exists in this organization' });
+ }
+ }
+
+ // Create the contact
+ const contact = await prisma.contact.create({
+ data: {
+ firstName,
+ lastName,
+ email: email || null,
+ phone: phone || null,
+ title: title || null,
+ department: department || null,
+ street: street || null,
+ city: city || null,
+ state: state || null,
+ postalCode: postalCode || null,
+ country: country || null,
+ description: description || null,
+ organizationId: req.organizationId,
+ ownerId: req.userId
+ }
+ });
+
+ // Create account-contact relationship if accountId is provided
+ if (accountId) {
+ await prisma.accountContactRelationship.create({
+ data: {
+ accountId: accountId,
+ contactId: contact.id,
+ isPrimary: true
+ }
+ });
+ }
+
+ // Fetch the created contact with relationships
+ const createdContact = await prisma.contact.findUnique({
+ where: { id: contact.id },
+ include: {
+ relatedAccounts: {
+ include: {
+ account: {
+ select: { id: true, name: true }
+ }
+ }
+ },
+ owner: {
+ select: { id: true, name: true, email: true }
+ }
+ }
+ });
+
+ res.status(201).json(createdContact);
+ } catch (error) {
+ console.error('Create contact error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+/**
+ * @swagger
+ * /contacts/{id}:
+ * get:
+ * summary: Get a specific contact by ID
+ * tags: [Contacts]
+ * parameters:
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * - in: path
+ * name: id
+ * required: true
+ * schema:
+ * type: string
+ * description: Contact ID
+ * responses:
+ * 200:
+ * description: Contact details
+ * 404:
+ * description: Contact not found
+ */
+router.get('/:id', async (req, res) => {
+ try {
+ const { id } = req.params;
+
+ const contact = await prisma.contact.findFirst({
+ where: {
+ id: id,
+ organizationId: req.organizationId
+ },
+ include: {
+ relatedAccounts: {
+ include: {
+ account: {
+ select: { id: true, name: true, type: true, website: true, phone: true }
+ }
+ }
+ },
+ owner: {
+ select: { id: true, name: true, email: true }
+ },
+ organization: {
+ select: { id: true, name: true }
+ }
+ }
+ });
+
+ if (!contact) {
+ return res.status(404).json({ error: 'Contact not found' });
+ }
+
+ res.json(contact);
+ } catch (error) {
+ console.error('Get contact details error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+export default router;
\ No newline at end of file
diff --git a/api/routes/dashboard.js b/api/routes/dashboard.js
new file mode 100644
index 0000000..317ac4f
--- /dev/null
+++ b/api/routes/dashboard.js
@@ -0,0 +1,374 @@
+import express from 'express';
+import { PrismaClient } from '@prisma/client';
+import { verifyToken, requireOrganization } from '../middleware/auth.js';
+
+const router = express.Router();
+const prisma = new PrismaClient();
+
+/**
+ * @swagger
+ * components:
+ * schemas:
+ * DashboardMetrics:
+ * type: object
+ * properties:
+ * totalLeads:
+ * type: integer
+ * description: Number of active leads
+ * totalOpportunities:
+ * type: integer
+ * description: Number of open opportunities
+ * totalAccounts:
+ * type: integer
+ * description: Number of active accounts
+ * totalContacts:
+ * type: integer
+ * description: Number of contacts
+ * pendingTasks:
+ * type: integer
+ * description: Number of pending tasks for the user
+ * opportunityRevenue:
+ * type: number
+ * description: Total pipeline value
+ * DashboardRecentData:
+ * type: object
+ * properties:
+ * leads:
+ * type: array
+ * items:
+ * type: object
+ * properties:
+ * id:
+ * type: string
+ * firstName:
+ * type: string
+ * lastName:
+ * type: string
+ * company:
+ * type: string
+ * status:
+ * type: string
+ * createdAt:
+ * type: string
+ * format: date-time
+ * opportunities:
+ * type: array
+ * items:
+ * type: object
+ * properties:
+ * id:
+ * type: string
+ * name:
+ * type: string
+ * amount:
+ * type: number
+ * account:
+ * type: object
+ * properties:
+ * name:
+ * type: string
+ * createdAt:
+ * type: string
+ * format: date-time
+ * tasks:
+ * type: array
+ * items:
+ * type: object
+ * properties:
+ * id:
+ * type: string
+ * subject:
+ * type: string
+ * status:
+ * type: string
+ * priority:
+ * type: string
+ * dueDate:
+ * type: string
+ * format: date-time
+ * activities:
+ * type: array
+ * items:
+ * type: object
+ * properties:
+ * id:
+ * type: string
+ * action:
+ * type: string
+ * entityType:
+ * type: string
+ * description:
+ * type: string
+ * timestamp:
+ * type: string
+ * format: date-time
+ * user:
+ * type: object
+ * properties:
+ * name:
+ * type: string
+ * DashboardResponse:
+ * type: object
+ * properties:
+ * success:
+ * type: boolean
+ * metrics:
+ * $ref: '#/components/schemas/DashboardMetrics'
+ * recentData:
+ * $ref: '#/components/schemas/DashboardRecentData'
+ */
+
+/**
+ * @swagger
+ * /dashboard:
+ * get:
+ * summary: Get dashboard data with metrics and recent activity
+ * tags: [Dashboard]
+ * security:
+ * - bearerAuth: []
+ * parameters:
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * description: Organization ID
+ * responses:
+ * 200:
+ * description: Dashboard data retrieved successfully
+ * content:
+ * application/json:
+ * schema:
+ * $ref: '#/components/schemas/DashboardResponse'
+ * 400:
+ * description: Missing organization ID
+ * 401:
+ * description: Unauthorized
+ * 403:
+ * description: Access denied to organization
+ * 500:
+ * description: Internal server error
+ */
+router.get('/', verifyToken, requireOrganization, async (req, res) => {
+ try {
+ const userId = req.userId;
+ const organizationId = req.organizationId;
+
+ // Fetch dashboard metrics - parallel execution for performance
+ const [
+ totalLeads,
+ totalOpportunities,
+ totalAccounts,
+ totalContacts,
+ pendingTasks,
+ recentLeads,
+ recentOpportunities,
+ upcomingTasks,
+ recentActivities
+ ] = await Promise.all([
+ // Count metrics
+ prisma.lead.count({
+ where: { organizationId, isConverted: false }
+ }),
+ prisma.opportunity.count({
+ where: { organizationId, stage: { not: 'CLOSED_WON' } }
+ }),
+ prisma.account.count({
+ where: { organizationId, isActive: true }
+ }),
+ prisma.contact.count({
+ where: { organizationId }
+ }),
+ prisma.task.count({
+ where: {
+ organizationId,
+ status: { not: 'Completed' },
+ ownerId: userId
+ }
+ }),
+
+ // Recent data
+ prisma.lead.findMany({
+ where: { organizationId },
+ orderBy: { createdAt: 'desc' },
+ take: 5,
+ select: {
+ id: true,
+ firstName: true,
+ lastName: true,
+ company: true,
+ status: true,
+ createdAt: true
+ }
+ }),
+ prisma.opportunity.findMany({
+ where: { organizationId },
+ orderBy: { createdAt: 'desc' },
+ take: 5,
+ include: {
+ account: {
+ select: { name: true }
+ }
+ }
+ }),
+ prisma.task.findMany({
+ where: {
+ organizationId,
+ ownerId: userId,
+ status: { not: 'Completed' },
+ dueDate: { gte: new Date() }
+ },
+ orderBy: { dueDate: 'asc' },
+ take: 5,
+ select: {
+ id: true,
+ subject: true,
+ status: true,
+ priority: true,
+ dueDate: true
+ }
+ }),
+ prisma.auditLog.findMany({
+ where: { organizationId },
+ orderBy: { timestamp: 'desc' },
+ take: 10,
+ include: {
+ user: {
+ select: { name: true }
+ }
+ }
+ })
+ ]);
+
+ // Calculate opportunity revenue
+ const opportunityRevenue = await prisma.opportunity.aggregate({
+ where: { organizationId },
+ _sum: { amount: true }
+ });
+
+ const response = {
+ success: true,
+ metrics: {
+ totalLeads,
+ totalOpportunities,
+ totalAccounts,
+ totalContacts,
+ pendingTasks,
+ opportunityRevenue: opportunityRevenue._sum.amount || 0
+ },
+ recentData: {
+ leads: recentLeads,
+ opportunities: recentOpportunities,
+ tasks: upcomingTasks,
+ activities: recentActivities
+ }
+ };
+
+ res.json(response);
+ } catch (error) {
+ console.error('Dashboard API error:', error);
+ res.status(500).json({
+ success: false,
+ error: 'Failed to load dashboard data'
+ });
+ }
+});
+
+/**
+ * @swagger
+ * /dashboard/metrics:
+ * get:
+ * summary: Get dashboard metrics only (lightweight endpoint)
+ * tags: [Dashboard]
+ * security:
+ * - bearerAuth: []
+ * parameters:
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * description: Organization ID
+ * responses:
+ * 200:
+ * description: Dashboard metrics retrieved successfully
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * properties:
+ * success:
+ * type: boolean
+ * metrics:
+ * $ref: '#/components/schemas/DashboardMetrics'
+ * 400:
+ * description: Missing organization ID
+ * 401:
+ * description: Unauthorized
+ * 403:
+ * description: Access denied to organization
+ * 500:
+ * description: Internal server error
+ */
+router.get('/metrics', verifyToken, requireOrganization, async (req, res) => {
+ try {
+ const userId = req.userId;
+ const organizationId = req.organizationId;
+
+ // Fetch only metrics for lightweight response
+ const [
+ totalLeads,
+ totalOpportunities,
+ totalAccounts,
+ totalContacts,
+ pendingTasks,
+ opportunityRevenue
+ ] = await Promise.all([
+ prisma.lead.count({
+ where: { organizationId, isConverted: false }
+ }),
+ prisma.opportunity.count({
+ where: { organizationId, stage: { not: 'CLOSED_WON' } }
+ }),
+ prisma.account.count({
+ where: { organizationId, isActive: true }
+ }),
+ prisma.contact.count({
+ where: { organizationId }
+ }),
+ prisma.task.count({
+ where: {
+ organizationId,
+ status: { not: 'Completed' },
+ ownerId: userId
+ }
+ }),
+ prisma.opportunity.aggregate({
+ where: { organizationId },
+ _sum: { amount: true }
+ })
+ ]);
+
+ const response = {
+ success: true,
+ metrics: {
+ totalLeads,
+ totalOpportunities,
+ totalAccounts,
+ totalContacts,
+ pendingTasks,
+ opportunityRevenue: opportunityRevenue._sum.amount || 0
+ }
+ };
+
+ res.json(response);
+ } catch (error) {
+ console.error('Dashboard metrics API error:', error);
+ res.status(500).json({
+ success: false,
+ error: 'Failed to load dashboard metrics'
+ });
+ }
+});
+
+export default router;
\ No newline at end of file
diff --git a/api/routes/leads.js b/api/routes/leads.js
new file mode 100644
index 0000000..53fd957
--- /dev/null
+++ b/api/routes/leads.js
@@ -0,0 +1,344 @@
+import express from 'express';
+import { PrismaClient } from '@prisma/client';
+import { verifyToken, requireOrganization } from '../middleware/auth.js';
+
+const router = express.Router();
+const prisma = new PrismaClient();
+
+router.use(verifyToken);
+router.use(requireOrganization);
+
+/**
+ * @swagger
+ * /leads/metadata:
+ * get:
+ * summary: Get leads metadata (enums, options, etc.)
+ * tags: [Leads]
+ * responses:
+ * 200:
+ * description: Leads metadata
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * properties:
+ * leadStatuses:
+ * type: array
+ * items:
+ * type: string
+ * leadSources:
+ * type: array
+ * items:
+ * type: string
+ * ratings:
+ * type: array
+ * items:
+ * type: string
+ * industries:
+ * type: array
+ * items:
+ * type: string
+ */
+router.get('/metadata', async (req, res) => {
+ try {
+ const metadata = {
+ leadStatuses: [
+ 'NEW',
+ 'PENDING',
+ 'CONTACTED',
+ 'QUALIFIED',
+ 'UNQUALIFIED',
+ 'CONVERTED'
+ ],
+ leadSources: [
+ 'WEB',
+ 'PHONE_INQUIRY',
+ 'PARTNER_REFERRAL',
+ 'COLD_CALL',
+ 'TRADE_SHOW',
+ 'EMPLOYEE_REFERRAL',
+ 'ADVERTISEMENT',
+ 'OTHER'
+ ],
+ ratings: [
+ 'Hot',
+ 'Warm',
+ 'Cold'
+ ],
+ industries: [
+ 'Technology',
+ 'Healthcare',
+ 'Finance',
+ 'Education',
+ 'Manufacturing',
+ 'Retail',
+ 'Real Estate',
+ 'Consulting',
+ 'Media',
+ 'Transportation',
+ 'Energy',
+ 'Government',
+ 'Non-profit',
+ 'Other'
+ ]
+ };
+
+ res.json(metadata);
+ } catch (error) {
+ console.error('Get leads metadata error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+/**
+ * @swagger
+ * components:
+ * schemas:
+ * Lead:
+ * type: object
+ * properties:
+ * id:
+ * type: string
+ * firstName:
+ * type: string
+ * lastName:
+ * type: string
+ * email:
+ * type: string
+ * phone:
+ * type: string
+ * company:
+ * type: string
+ * title:
+ * type: string
+ * status:
+ * type: string
+ * enum: [NEW, PENDING, CONTACTED, QUALIFIED, UNQUALIFIED, CONVERTED]
+ * leadSource:
+ * type: string
+ * enum: [WEB, PHONE_INQUIRY, PARTNER_REFERRAL, COLD_CALL, TRADE_SHOW, EMPLOYEE_REFERRAL, ADVERTISEMENT, OTHER]
+ * industry:
+ * type: string
+ * rating:
+ * type: string
+ * enum: [Hot, Warm, Cold]
+ * description:
+ * type: string
+ * isConverted:
+ * type: boolean
+ * convertedAt:
+ * type: string
+ * format: date-time
+ * createdAt:
+ * type: string
+ * format: date-time
+ * updatedAt:
+ * type: string
+ * format: date-time
+ */
+
+/**
+ * @swagger
+ * /leads:
+ * get:
+ * summary: Get all leads for organization
+ * tags: [Leads]
+ * parameters:
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * - in: query
+ * name: page
+ * schema:
+ * type: integer
+ * default: 1
+ * - in: query
+ * name: limit
+ * schema:
+ * type: integer
+ * default: 10
+ * responses:
+ * 200:
+ * description: List of leads
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * properties:
+ * leads:
+ * type: array
+ * items:
+ * $ref: '#/components/schemas/Lead'
+ * pagination:
+ * type: object
+ */
+router.get('/', async (req, res) => {
+ try {
+ const page = parseInt(req.query.page) || 1;
+ const limit = parseInt(req.query.limit) || 10;
+ const skip = (page - 1) * limit;
+
+ const [leads, total] = await Promise.all([
+ prisma.lead.findMany({
+ where: { organizationId: req.organizationId },
+ skip,
+ take: limit,
+ orderBy: { createdAt: 'desc' },
+ include: {
+ owner: {
+ select: { id: true, name: true, email: true }
+ }
+ }
+ }),
+ prisma.lead.count({
+ where: { organizationId: req.organizationId }
+ })
+ ]);
+
+ res.json({
+ leads,
+ pagination: {
+ page,
+ limit,
+ total,
+ pages: Math.ceil(total / limit)
+ }
+ });
+ } catch (error) {
+ console.error('Get leads error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+/**
+ * @swagger
+ * /leads/{id}:
+ * get:
+ * summary: Get lead by ID
+ * tags: [Leads]
+ * parameters:
+ * - in: path
+ * name: id
+ * required: true
+ * schema:
+ * type: string
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * responses:
+ * 200:
+ * description: Lead details
+ * content:
+ * application/json:
+ * schema:
+ * $ref: '#/components/schemas/Lead'
+ * 404:
+ * description: Lead not found
+ */
+router.get('/:id', async (req, res) => {
+ try {
+ const lead = await prisma.lead.findFirst({
+ where: {
+ id: req.params.id,
+ organizationId: req.organizationId
+ },
+ include: {
+ owner: {
+ select: { id: true, name: true, email: true }
+ }
+ }
+ });
+
+ if (!lead) {
+ return res.status(404).json({ error: 'Lead not found' });
+ }
+
+ res.json(lead);
+ } catch (error) {
+ console.error('Get lead error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+/**
+ * @swagger
+ * /leads:
+ * post:
+ * summary: Create a new lead
+ * tags: [Leads]
+ * parameters:
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * requestBody:
+ * required: true
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * required:
+ * - firstName
+ * - lastName
+ * - email
+ * properties:
+ * firstName:
+ * type: string
+ * lastName:
+ * type: string
+ * email:
+ * type: string
+ * phone:
+ * type: string
+ * company:
+ * type: string
+ * status:
+ * type: string
+ * leadSource:
+ * type: string
+ * responses:
+ * 201:
+ * description: Lead created successfully
+ * 400:
+ * description: Invalid input
+ */
+router.post('/', async (req, res) => {
+ try {
+ const { firstName, lastName, email, phone, company, status, leadSource } = req.body;
+
+ if (!firstName || !lastName || !email) {
+ return res.status(400).json({ error: 'First name, last name, and email are required' });
+ }
+
+ const lead = await prisma.lead.create({
+ data: {
+ firstName,
+ lastName,
+ email,
+ phone,
+ company,
+ status: status || 'NEW',
+ leadSource,
+ organizationId: req.organizationId,
+ ownerId: req.userId
+ },
+ include: {
+ owner: {
+ select: { id: true, name: true, email: true }
+ }
+ }
+ });
+
+ res.status(201).json(lead);
+ } catch (error) {
+ console.error('Create lead error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+export default router;
\ No newline at end of file
diff --git a/api/routes/opportunities.js b/api/routes/opportunities.js
new file mode 100644
index 0000000..9c16649
--- /dev/null
+++ b/api/routes/opportunities.js
@@ -0,0 +1,136 @@
+import express from 'express';
+import { PrismaClient } from '@prisma/client';
+import { verifyToken, requireOrganization } from '../middleware/auth.js';
+
+const router = express.Router();
+const prisma = new PrismaClient();
+
+router.use(verifyToken);
+router.use(requireOrganization);
+
+/**
+ * @swagger
+ * /opportunities:
+ * get:
+ * summary: Get all opportunities for organization
+ * tags: [Opportunities]
+ * parameters:
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * responses:
+ * 200:
+ * description: List of opportunities
+ */
+router.get('/', async (req, res) => {
+ try {
+ const opportunities = await prisma.opportunity.findMany({
+ where: { organizationId: req.organizationId },
+ orderBy: { createdAt: 'desc' },
+ include: {
+ account: {
+ select: { id: true, name: true }
+ },
+ owner: {
+ select: { id: true, firstName: true, lastName: true, email: true }
+ }
+ }
+ });
+
+ res.json({ opportunities });
+ } catch (error) {
+ console.error('Get opportunities error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+/**
+ * @swagger
+ * /opportunities:
+ * post:
+ * summary: Create a new opportunity
+ * tags: [Opportunities]
+ * parameters:
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * requestBody:
+ * required: true
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * required:
+ * - name
+ * - amount
+ * - closeDate
+ * - stage
+ * properties:
+ * name:
+ * type: string
+ * amount:
+ * type: number
+ * closeDate:
+ * type: string
+ * format: date
+ * stage:
+ * type: string
+ * accountId:
+ * type: string
+ * responses:
+ * 201:
+ * description: Opportunity created successfully
+ */
+router.post('/', async (req, res) => {
+ try {
+ const { name, amount, closeDate, stage, accountId } = req.body;
+
+ if (!name || !amount || !closeDate || !stage) {
+ return res.status(400).json({ error: 'Name, amount, close date, and stage are required' });
+ }
+
+ if (accountId) {
+ const account = await prisma.account.findFirst({
+ where: {
+ id: accountId,
+ organizationId: req.organizationId
+ }
+ });
+
+ if (!account) {
+ return res.status(400).json({ error: 'Account not found in your organization' });
+ }
+ }
+
+ const opportunity = await prisma.opportunity.create({
+ data: {
+ name,
+ amount: parseFloat(amount),
+ closeDate: new Date(closeDate),
+ stage,
+ accountId,
+ organizationId: req.organizationId,
+ ownerId: req.userId
+ },
+ include: {
+ account: {
+ select: { id: true, name: true }
+ },
+ owner: {
+ select: { id: true, firstName: true, lastName: true, email: true }
+ }
+ }
+ });
+
+ res.status(201).json(opportunity);
+ } catch (error) {
+ console.error('Create opportunity error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+export default router;
\ No newline at end of file
diff --git a/api/routes/tasks.js b/api/routes/tasks.js
new file mode 100644
index 0000000..057c090
--- /dev/null
+++ b/api/routes/tasks.js
@@ -0,0 +1,863 @@
+import express from 'express';
+import { PrismaClient } from '@prisma/client';
+import { verifyToken, requireOrganization } from '../middleware/auth.js';
+
+const router = express.Router();
+const prisma = new PrismaClient();
+
+router.use(verifyToken);
+router.use(requireOrganization);
+
+/**
+ * @swagger
+ * components:
+ * schemas:
+ * Task:
+ * type: object
+ * properties:
+ * id:
+ * type: string
+ * subject:
+ * type: string
+ * status:
+ * type: string
+ * enum: [Not Started, In Progress, Completed, Deferred, Waiting]
+ * priority:
+ * type: string
+ * enum: [High, Normal, Low]
+ * dueDate:
+ * type: string
+ * format: date-time
+ * description:
+ * type: string
+ * createdAt:
+ * type: string
+ * format: date-time
+ * updatedAt:
+ * type: string
+ * format: date-time
+ */
+
+/**
+ * @swagger
+ * /tasks:
+ * get:
+ * summary: Get all tasks for organization
+ * tags: [Tasks]
+ * parameters:
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * - in: query
+ * name: status
+ * schema:
+ * type: string
+ * description: Filter tasks by status
+ * - in: query
+ * name: priority
+ * schema:
+ * type: string
+ * description: Filter tasks by priority
+ * - in: query
+ * name: ownerId
+ * schema:
+ * type: string
+ * description: Filter tasks by owner ID
+ * - in: query
+ * name: accountId
+ * schema:
+ * type: string
+ * description: Filter tasks by account ID
+ * - in: query
+ * name: contactId
+ * schema:
+ * type: string
+ * description: Filter tasks by contact ID
+ * - in: query
+ * name: leadId
+ * schema:
+ * type: string
+ * description: Filter tasks by lead ID
+ * - in: query
+ * name: opportunityId
+ * schema:
+ * type: string
+ * description: Filter tasks by opportunity ID
+ * - in: query
+ * name: caseId
+ * schema:
+ * type: string
+ * description: Filter tasks by case ID
+ * - in: query
+ * name: limit
+ * schema:
+ * type: integer
+ * default: 50
+ * description: Limit number of results
+ * - in: query
+ * name: offset
+ * schema:
+ * type: integer
+ * default: 0
+ * description: Offset for pagination
+ * responses:
+ * 200:
+ * description: List of tasks
+ */
+router.get('/', async (req, res) => {
+ try {
+ const {
+ status,
+ priority,
+ ownerId,
+ accountId,
+ contactId,
+ leadId,
+ opportunityId,
+ caseId,
+ limit = 50,
+ offset = 0
+ } = req.query;
+
+ // Build where clause for filtering
+ const where = {
+ organizationId: req.organizationId,
+ ...(status && { status }),
+ ...(priority && { priority }),
+ ...(ownerId && { ownerId }),
+ ...(accountId && { accountId }),
+ ...(contactId && { contactId }),
+ ...(leadId && { leadId }),
+ ...(opportunityId && { opportunityId }),
+ ...(caseId && { caseId })
+ };
+
+ const tasks = await prisma.task.findMany({
+ where,
+ orderBy: { createdAt: 'desc' },
+ take: parseInt(limit),
+ skip: parseInt(offset),
+ include: {
+ owner: {
+ select: { id: true, name: true, email: true }
+ },
+ createdBy: {
+ select: { id: true, name: true, email: true }
+ },
+ account: {
+ select: { id: true, name: true, type: true }
+ },
+ contact: {
+ select: { id: true, firstName: true, lastName: true, email: true }
+ },
+ lead: {
+ select: { id: true, firstName: true, lastName: true, email: true, company: true }
+ },
+ opportunity: {
+ select: { id: true, name: true, amount: true, status: true }
+ },
+ case: {
+ select: { id: true, caseNumber: true, subject: true, status: true }
+ }
+ }
+ });
+
+ // Get total count for pagination
+ const totalCount = await prisma.task.count({ where });
+
+ res.json({
+ tasks,
+ pagination: {
+ total: totalCount,
+ limit: parseInt(limit),
+ offset: parseInt(offset),
+ hasMore: parseInt(offset) + parseInt(limit) < totalCount
+ }
+ });
+ } catch (error) {
+ console.error('Get tasks error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+/**
+ * @swagger
+ * /tasks:
+ * post:
+ * summary: Create a new task
+ * tags: [Tasks]
+ * parameters:
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * requestBody:
+ * required: true
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * required:
+ * - subject
+ * properties:
+ * subject:
+ * type: string
+ * status:
+ * type: string
+ * enum: [Not Started, In Progress, Completed, Deferred, Waiting]
+ * default: Not Started
+ * priority:
+ * type: string
+ * enum: [High, Normal, Low]
+ * default: Normal
+ * dueDate:
+ * type: string
+ * format: date-time
+ * description:
+ * type: string
+ * ownerId:
+ * type: string
+ * description: UUID of the user who owns this task
+ * accountId:
+ * type: string
+ * description: UUID of the related account
+ * contactId:
+ * type: string
+ * description: UUID of the related contact
+ * leadId:
+ * type: string
+ * description: UUID of the related lead
+ * opportunityId:
+ * type: string
+ * description: UUID of the related opportunity
+ * caseId:
+ * type: string
+ * description: UUID of the related case
+ * responses:
+ * 201:
+ * description: Task created successfully
+ * 400:
+ * description: Validation error
+ */
+router.post('/', async (req, res) => {
+ try {
+ const {
+ subject,
+ status = 'Not Started',
+ priority = 'Normal',
+ dueDate,
+ description,
+ ownerId,
+ accountId,
+ contactId,
+ leadId,
+ opportunityId,
+ caseId
+ } = req.body;
+
+ if (!subject) {
+ return res.status(400).json({ error: 'Subject is required' });
+ }
+
+ // Validate status
+ const validStatuses = ['Not Started', 'In Progress', 'Completed', 'Deferred', 'Waiting'];
+ if (status && !validStatuses.includes(status)) {
+ return res.status(400).json({ error: 'Invalid status. Valid options: ' + validStatuses.join(', ') });
+ }
+
+ // Validate priority
+ const validPriorities = ['High', 'Normal', 'Low'];
+ if (priority && !validPriorities.includes(priority)) {
+ return res.status(400).json({ error: 'Invalid priority. Valid options: ' + validPriorities.join(', ') });
+ }
+
+ // Validate owner exists in organization
+ let owner = null;
+ const finalOwnerId = ownerId || req.userId; // Default to current user if no owner specified
+
+ const userOrg = await prisma.userOrganization.findFirst({
+ where: {
+ userId: finalOwnerId,
+ organizationId: req.organizationId
+ },
+ include: {
+ user: true
+ }
+ });
+
+ if (!userOrg) {
+ return res.status(400).json({ error: 'Owner must be a member of this organization' });
+ }
+
+ // Validate related entities if provided
+ if (accountId) {
+ const account = await prisma.account.findFirst({
+ where: {
+ id: accountId,
+ organizationId: req.organizationId
+ }
+ });
+ if (!account) {
+ return res.status(400).json({ error: 'Account not found in your organization' });
+ }
+ }
+
+ if (contactId) {
+ const contact = await prisma.contact.findFirst({
+ where: {
+ id: contactId,
+ organizationId: req.organizationId
+ }
+ });
+ if (!contact) {
+ return res.status(400).json({ error: 'Contact not found in your organization' });
+ }
+ }
+
+ if (leadId) {
+ const lead = await prisma.lead.findFirst({
+ where: {
+ id: leadId,
+ organizationId: req.organizationId
+ }
+ });
+ if (!lead) {
+ return res.status(400).json({ error: 'Lead not found in your organization' });
+ }
+ }
+
+ if (opportunityId) {
+ const opportunity = await prisma.opportunity.findFirst({
+ where: {
+ id: opportunityId,
+ organizationId: req.organizationId
+ }
+ });
+ if (!opportunity) {
+ return res.status(400).json({ error: 'Opportunity not found in your organization' });
+ }
+ }
+
+ if (caseId) {
+ const caseRecord = await prisma.case.findFirst({
+ where: {
+ id: caseId,
+ organizationId: req.organizationId
+ }
+ });
+ if (!caseRecord) {
+ return res.status(400).json({ error: 'Case not found in your organization' });
+ }
+ }
+
+ // Create the task
+ const task = await prisma.task.create({
+ data: {
+ subject,
+ status,
+ priority,
+ dueDate: dueDate ? new Date(dueDate) : null,
+ description: description || null,
+ ownerId: finalOwnerId,
+ createdById: req.userId,
+ organizationId: req.organizationId,
+ accountId: accountId || null,
+ contactId: contactId || null,
+ leadId: leadId || null,
+ opportunityId: opportunityId || null,
+ caseId: caseId || null
+ },
+ include: {
+ owner: {
+ select: { id: true, name: true, email: true }
+ },
+ createdBy: {
+ select: { id: true, name: true, email: true }
+ },
+ account: {
+ select: { id: true, name: true, type: true }
+ },
+ contact: {
+ select: { id: true, firstName: true, lastName: true, email: true }
+ },
+ lead: {
+ select: { id: true, firstName: true, lastName: true, email: true, company: true }
+ },
+ opportunity: {
+ select: { id: true, name: true, amount: true, status: true }
+ },
+ case: {
+ select: { id: true, caseNumber: true, subject: true, status: true }
+ }
+ }
+ });
+
+ res.status(201).json(task);
+ } catch (error) {
+ console.error('Create task error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+/**
+ * @swagger
+ * /tasks/{id}:
+ * get:
+ * summary: Get a specific task by ID
+ * tags: [Tasks]
+ * parameters:
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * - in: path
+ * name: id
+ * required: true
+ * schema:
+ * type: string
+ * description: Task ID
+ * responses:
+ * 200:
+ * description: Task details
+ * 404:
+ * description: Task not found
+ */
+router.get('/:id', async (req, res) => {
+ try {
+ const { id } = req.params;
+
+ const task = await prisma.task.findFirst({
+ where: {
+ id: id,
+ organizationId: req.organizationId
+ },
+ include: {
+ owner: {
+ select: { id: true, name: true, email: true }
+ },
+ createdBy: {
+ select: { id: true, name: true, email: true }
+ },
+ account: {
+ select: { id: true, name: true, type: true, website: true, phone: true }
+ },
+ contact: {
+ select: { id: true, firstName: true, lastName: true, email: true, phone: true, title: true }
+ },
+ lead: {
+ select: { id: true, firstName: true, lastName: true, email: true, phone: true, company: true, status: true }
+ },
+ opportunity: {
+ select: { id: true, name: true, amount: true, status: true, stage: true, closeDate: true }
+ },
+ case: {
+ select: { id: true, caseNumber: true, subject: true, status: true, priority: true }
+ },
+ comments: {
+ include: {
+ author: {
+ select: { id: true, name: true, email: true }
+ }
+ },
+ orderBy: { createdAt: 'desc' }
+ },
+ organization: {
+ select: { id: true, name: true }
+ }
+ }
+ });
+
+ if (!task) {
+ return res.status(404).json({ error: 'Task not found' });
+ }
+
+ res.json(task);
+ } catch (error) {
+ console.error('Get task details error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+/**
+ * @swagger
+ * /tasks/{id}:
+ * put:
+ * summary: Update a specific task
+ * tags: [Tasks]
+ * parameters:
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * - in: path
+ * name: id
+ * required: true
+ * schema:
+ * type: string
+ * description: Task ID
+ * requestBody:
+ * required: true
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * properties:
+ * subject:
+ * type: string
+ * status:
+ * type: string
+ * enum: [Not Started, In Progress, Completed, Deferred, Waiting]
+ * priority:
+ * type: string
+ * enum: [High, Normal, Low]
+ * dueDate:
+ * type: string
+ * format: date-time
+ * description:
+ * type: string
+ * ownerId:
+ * type: string
+ * description: UUID of the user who owns this task
+ * accountId:
+ * type: string
+ * description: UUID of the related account
+ * contactId:
+ * type: string
+ * description: UUID of the related contact
+ * leadId:
+ * type: string
+ * description: UUID of the related lead
+ * opportunityId:
+ * type: string
+ * description: UUID of the related opportunity
+ * caseId:
+ * type: string
+ * description: UUID of the related case
+ * responses:
+ * 200:
+ * description: Task updated successfully
+ * 400:
+ * description: Validation error
+ * 404:
+ * description: Task not found
+ */
+router.put('/:id', async (req, res) => {
+ try {
+ const { id } = req.params;
+ const {
+ subject,
+ status,
+ priority,
+ dueDate,
+ description,
+ ownerId,
+ accountId,
+ contactId,
+ leadId,
+ opportunityId,
+ caseId
+ } = req.body;
+
+ // Check if task exists and belongs to organization
+ const existingTask = await prisma.task.findFirst({
+ where: {
+ id: id,
+ organizationId: req.organizationId
+ }
+ });
+
+ if (!existingTask) {
+ return res.status(404).json({ error: 'Task not found' });
+ }
+
+ // Validate status if provided
+ if (status) {
+ const validStatuses = ['Not Started', 'In Progress', 'Completed', 'Deferred', 'Waiting'];
+ if (!validStatuses.includes(status)) {
+ return res.status(400).json({ error: 'Invalid status. Valid options: ' + validStatuses.join(', ') });
+ }
+ }
+
+ // Validate priority if provided
+ if (priority) {
+ const validPriorities = ['High', 'Normal', 'Low'];
+ if (!validPriorities.includes(priority)) {
+ return res.status(400).json({ error: 'Invalid priority. Valid options: ' + validPriorities.join(', ') });
+ }
+ }
+
+ // Validate owner exists in organization if provided
+ if (ownerId) {
+ const userOrg = await prisma.userOrganization.findFirst({
+ where: {
+ userId: ownerId,
+ organizationId: req.organizationId
+ }
+ });
+
+ if (!userOrg) {
+ return res.status(400).json({ error: 'Owner must be a member of this organization' });
+ }
+ }
+
+ // Validate related entities if provided
+ if (accountId !== undefined) {
+ if (accountId) {
+ const account = await prisma.account.findFirst({
+ where: {
+ id: accountId,
+ organizationId: req.organizationId
+ }
+ });
+ if (!account) {
+ return res.status(400).json({ error: 'Account not found in your organization' });
+ }
+ }
+ }
+
+ if (contactId !== undefined) {
+ if (contactId) {
+ const contact = await prisma.contact.findFirst({
+ where: {
+ id: contactId,
+ organizationId: req.organizationId
+ }
+ });
+ if (!contact) {
+ return res.status(400).json({ error: 'Contact not found in your organization' });
+ }
+ }
+ }
+
+ if (leadId !== undefined) {
+ if (leadId) {
+ const lead = await prisma.lead.findFirst({
+ where: {
+ id: leadId,
+ organizationId: req.organizationId
+ }
+ });
+ if (!lead) {
+ return res.status(400).json({ error: 'Lead not found in your organization' });
+ }
+ }
+ }
+
+ if (opportunityId !== undefined) {
+ if (opportunityId) {
+ const opportunity = await prisma.opportunity.findFirst({
+ where: {
+ id: opportunityId,
+ organizationId: req.organizationId
+ }
+ });
+ if (!opportunity) {
+ return res.status(400).json({ error: 'Opportunity not found in your organization' });
+ }
+ }
+ }
+
+ if (caseId !== undefined) {
+ if (caseId) {
+ const caseRecord = await prisma.case.findFirst({
+ where: {
+ id: caseId,
+ organizationId: req.organizationId
+ }
+ });
+ if (!caseRecord) {
+ return res.status(400).json({ error: 'Case not found in your organization' });
+ }
+ }
+ }
+
+ // Build update data object
+ const updateData = {};
+ if (subject !== undefined) updateData.subject = subject;
+ if (status !== undefined) updateData.status = status;
+ if (priority !== undefined) updateData.priority = priority;
+ if (dueDate !== undefined) updateData.dueDate = dueDate ? new Date(dueDate) : null;
+ if (description !== undefined) updateData.description = description;
+ if (ownerId !== undefined) updateData.ownerId = ownerId;
+ if (accountId !== undefined) updateData.accountId = accountId;
+ if (contactId !== undefined) updateData.contactId = contactId;
+ if (leadId !== undefined) updateData.leadId = leadId;
+ if (opportunityId !== undefined) updateData.opportunityId = opportunityId;
+ if (caseId !== undefined) updateData.caseId = caseId;
+
+ // Update the task
+ const task = await prisma.task.update({
+ where: { id: id },
+ data: updateData,
+ include: {
+ owner: {
+ select: { id: true, name: true, email: true }
+ },
+ createdBy: {
+ select: { id: true, name: true, email: true }
+ },
+ account: {
+ select: { id: true, name: true, type: true }
+ },
+ contact: {
+ select: { id: true, firstName: true, lastName: true, email: true }
+ },
+ lead: {
+ select: { id: true, firstName: true, lastName: true, email: true, company: true }
+ },
+ opportunity: {
+ select: { id: true, name: true, amount: true, status: true }
+ },
+ case: {
+ select: { id: true, caseNumber: true, subject: true, status: true }
+ }
+ }
+ });
+
+ res.json(task);
+ } catch (error) {
+ console.error('Update task error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+/**
+ * @swagger
+ * /tasks/{id}:
+ * delete:
+ * summary: Delete a specific task
+ * tags: [Tasks]
+ * parameters:
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * - in: path
+ * name: id
+ * required: true
+ * schema:
+ * type: string
+ * description: Task ID
+ * responses:
+ * 200:
+ * description: Task deleted successfully
+ * 404:
+ * description: Task not found
+ */
+router.delete('/:id', async (req, res) => {
+ try {
+ const { id } = req.params;
+
+ // Check if task exists and belongs to organization
+ const existingTask = await prisma.task.findFirst({
+ where: {
+ id: id,
+ organizationId: req.organizationId
+ }
+ });
+
+ if (!existingTask) {
+ return res.status(404).json({ error: 'Task not found' });
+ }
+
+ // Delete the task (this will also cascade delete related comments due to schema relationship)
+ await prisma.task.delete({
+ where: { id: id }
+ });
+
+ res.json({ message: 'Task deleted successfully' });
+ } catch (error) {
+ console.error('Delete task error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+/**
+ * @swagger
+ * /tasks/{id}/comments:
+ * post:
+ * summary: Add a comment to a task
+ * tags: [Tasks]
+ * parameters:
+ * - in: header
+ * name: X-Organization-ID
+ * required: true
+ * schema:
+ * type: string
+ * - in: path
+ * name: id
+ * required: true
+ * schema:
+ * type: string
+ * description: Task ID
+ * requestBody:
+ * required: true
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * required:
+ * - body
+ * properties:
+ * body:
+ * type: string
+ * isPrivate:
+ * type: boolean
+ * default: false
+ * responses:
+ * 201:
+ * description: Comment added successfully
+ * 404:
+ * description: Task not found
+ */
+router.post('/:id/comments', async (req, res) => {
+ try {
+ const { id } = req.params;
+ const { body, isPrivate = false } = req.body;
+
+ if (!body) {
+ return res.status(400).json({ error: 'Comment body is required' });
+ }
+
+ // Check if task exists and belongs to organization
+ const existingTask = await prisma.task.findFirst({
+ where: {
+ id: id,
+ organizationId: req.organizationId
+ }
+ });
+
+ if (!existingTask) {
+ return res.status(404).json({ error: 'Task not found' });
+ }
+
+ // Create the comment
+ const comment = await prisma.comment.create({
+ data: {
+ body,
+ isPrivate,
+ authorId: req.userId,
+ organizationId: req.organizationId,
+ taskId: id
+ },
+ include: {
+ author: {
+ select: { id: true, name: true, email: true }
+ }
+ }
+ });
+
+ res.status(201).json(comment);
+ } catch (error) {
+ console.error('Add task comment error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
+export default router;
diff --git a/package.json b/package.json
index 35cdf35..8b94524 100644
--- a/package.json
+++ b/package.json
@@ -11,30 +11,40 @@
"check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch",
"format": "prettier --write .",
- "lint": "prettier --check . && eslint ."
+ "lint": "prettier --check . && eslint .",
+ "api:dev": "nodemon server.js",
+ "api:start": "node server.js"
},
"devDependencies": {
- "@eslint/compat": "^1.2.9",
- "@eslint/js": "^9.28.0",
- "@sveltejs/adapter-node": "^5.2.12",
- "@sveltejs/kit": "^2.21.4",
- "@sveltejs/vite-plugin-svelte": "^5.1.0",
+ "@eslint/compat": "^1.3.1",
+ "@eslint/js": "^9.31.0",
+ "@sveltejs/adapter-node": "^5.2.13",
+ "@sveltejs/kit": "^2.25.2",
+ "@sveltejs/vite-plugin-svelte": "^6.1.0",
"@tailwindcss/typography": "^0.5.16",
- "@tailwindcss/vite": "^4.1.8",
- "eslint": "^9.28.0",
- "eslint-config-prettier": "^10.1.5",
- "eslint-plugin-svelte": "^3.9.2",
- "globals": "^16.2.0",
- "prettier": "^3.5.3",
+ "@tailwindcss/vite": "^4.1.11",
+ "@types/bcryptjs": "^3.0.0",
+ "@types/cors": "^2.8.19",
+ "@types/express": "^5.0.3",
+ "@types/jsonwebtoken": "^9.0.10",
+ "@types/morgan": "^1.9.10",
+ "@types/swagger-jsdoc": "^6.0.4",
+ "@types/swagger-ui-express": "^4.1.8",
+ "eslint": "^9.31.0",
+ "eslint-config-prettier": "^10.1.8",
+ "eslint-plugin-svelte": "^3.11.0",
+ "globals": "^16.3.0",
+ "nodemon": "^3.1.10",
+ "prettier": "^3.6.2",
"prettier-plugin-svelte": "^3.4.0",
- "prettier-plugin-tailwindcss": "^0.6.12",
- "prisma": "6.5.0",
- "svelte": "^5.33.18",
- "svelte-check": "^4.2.1",
- "svelte-dnd-action": "^0.9.61",
- "tailwindcss": "^4.1.8",
+ "prettier-plugin-tailwindcss": "^0.6.14",
+ "prisma": "6.12.0",
+ "svelte": "^5.36.14",
+ "svelte-check": "^4.3.0",
+ "svelte-dnd-action": "^0.9.64",
+ "tailwindcss": "^4.1.11",
"typescript": "^5.8.3",
- "vite": "^6.3.5"
+ "vite": "^7.0.5"
},
"pnpm": {
"onlyBuiltDependencies": [
@@ -42,15 +52,27 @@
]
},
"dependencies": {
- "@lucide/svelte": "^0.513.0",
- "@prisma/client": "6.5.0",
- "axios": "^1.9.0",
+ "@lucide/svelte": "^0.525.0",
+ "@prisma/client": "6.12.0",
+ "axios": "^1.11.0",
+ "bcryptjs": "^3.0.2",
+ "cors": "^2.8.5",
"date-fns": "^4.1.0",
- "libphonenumber-js": "^1.12.9",
- "marked": "^15.0.12",
+ "dotenv": "^17.2.1",
+ "express": "^5.1.0",
+ "express-rate-limit": "^8.0.1",
+ "google-auth-library": "^10.2.0",
+ "helmet": "^8.1.0",
+ "jsonwebtoken": "^9.0.2",
+ "libphonenumber-js": "^1.12.10",
+ "marked": "^16.1.1",
+ "morgan": "^1.10.1",
"svelte-highlight": "^7.8.3",
"svelte-meta-tags": "^4.4.0",
+ "swagger-jsdoc": "^6.2.8",
+ "swagger-ui-express": "^5.0.1",
"uuid": "^11.1.0",
- "zod": "^3.25.57"
+ "winston": "^3.17.0",
+ "zod": "^4.0.8"
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1278876..146bea0 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9,99 +9,159 @@ importers:
.:
dependencies:
'@lucide/svelte':
- specifier: ^0.513.0
- version: 0.513.0(svelte@5.33.18)
+ specifier: ^0.525.0
+ version: 0.525.0(svelte@5.36.14)
'@prisma/client':
- specifier: 6.5.0
- version: 6.5.0(prisma@6.5.0(typescript@5.8.3))(typescript@5.8.3)
+ specifier: 6.12.0
+ version: 6.12.0(prisma@6.12.0(typescript@5.8.3))(typescript@5.8.3)
axios:
- specifier: ^1.9.0
- version: 1.9.0
+ specifier: ^1.11.0
+ version: 1.11.0
+ bcryptjs:
+ specifier: ^3.0.2
+ version: 3.0.2
+ cors:
+ specifier: ^2.8.5
+ version: 2.8.5
date-fns:
specifier: ^4.1.0
version: 4.1.0
+ dotenv:
+ specifier: ^17.2.1
+ version: 17.2.1
+ express:
+ specifier: ^5.1.0
+ version: 5.1.0
+ express-rate-limit:
+ specifier: ^8.0.1
+ version: 8.0.1(express@5.1.0)
+ google-auth-library:
+ specifier: ^10.2.0
+ version: 10.2.0
+ helmet:
+ specifier: ^8.1.0
+ version: 8.1.0
+ jsonwebtoken:
+ specifier: ^9.0.2
+ version: 9.0.2
libphonenumber-js:
- specifier: ^1.12.9
- version: 1.12.9
+ specifier: ^1.12.10
+ version: 1.12.10
marked:
- specifier: ^15.0.12
- version: 15.0.12
+ specifier: ^16.1.1
+ version: 16.1.1
+ morgan:
+ specifier: ^1.10.1
+ version: 1.10.1
svelte-highlight:
specifier: ^7.8.3
version: 7.8.3
svelte-meta-tags:
specifier: ^4.4.0
- version: 4.4.0(svelte@5.33.18)
+ version: 4.4.0(svelte@5.36.14)
+ swagger-jsdoc:
+ specifier: ^6.2.8
+ version: 6.2.8(openapi-types@12.1.3)
+ swagger-ui-express:
+ specifier: ^5.0.1
+ version: 5.0.1(express@5.1.0)
uuid:
specifier: ^11.1.0
version: 11.1.0
+ winston:
+ specifier: ^3.17.0
+ version: 3.17.0
zod:
- specifier: ^3.25.57
- version: 3.25.57
+ specifier: ^4.0.8
+ version: 4.0.8
devDependencies:
'@eslint/compat':
- specifier: ^1.2.9
- version: 1.2.9(eslint@9.28.0(jiti@2.4.2))
+ specifier: ^1.3.1
+ version: 1.3.1(eslint@9.31.0(jiti@2.4.2))
'@eslint/js':
- specifier: ^9.28.0
- version: 9.28.0
+ specifier: ^9.31.0
+ version: 9.31.0
'@sveltejs/adapter-node':
- specifier: ^5.2.12
- version: 5.2.12(@sveltejs/kit@2.21.4(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))
+ specifier: ^5.2.13
+ version: 5.2.13(@sveltejs/kit@2.25.2(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1)))
'@sveltejs/kit':
- specifier: ^2.21.4
- version: 2.21.4(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
+ specifier: ^2.25.2
+ version: 2.25.2(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1))
'@sveltejs/vite-plugin-svelte':
- specifier: ^5.1.0
- version: 5.1.0(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
+ specifier: ^6.1.0
+ version: 6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1))
'@tailwindcss/typography':
specifier: ^0.5.16
- version: 0.5.16(tailwindcss@4.1.8)
+ version: 0.5.16(tailwindcss@4.1.11)
'@tailwindcss/vite':
+ specifier: ^4.1.11
+ version: 4.1.11(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1))
+ '@types/bcryptjs':
+ specifier: ^3.0.0
+ version: 3.0.0
+ '@types/cors':
+ specifier: ^2.8.19
+ version: 2.8.19
+ '@types/express':
+ specifier: ^5.0.3
+ version: 5.0.3
+ '@types/jsonwebtoken':
+ specifier: ^9.0.10
+ version: 9.0.10
+ '@types/morgan':
+ specifier: ^1.9.10
+ version: 1.9.10
+ '@types/swagger-jsdoc':
+ specifier: ^6.0.4
+ version: 6.0.4
+ '@types/swagger-ui-express':
specifier: ^4.1.8
- version: 4.1.8(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
+ version: 4.1.8
eslint:
- specifier: ^9.28.0
- version: 9.28.0(jiti@2.4.2)
+ specifier: ^9.31.0
+ version: 9.31.0(jiti@2.4.2)
eslint-config-prettier:
- specifier: ^10.1.5
- version: 10.1.5(eslint@9.28.0(jiti@2.4.2))
+ specifier: ^10.1.8
+ version: 10.1.8(eslint@9.31.0(jiti@2.4.2))
eslint-plugin-svelte:
- specifier: ^3.9.2
- version: 3.9.2(eslint@9.28.0(jiti@2.4.2))(svelte@5.33.18)
+ specifier: ^3.11.0
+ version: 3.11.0(eslint@9.31.0(jiti@2.4.2))(svelte@5.36.14)
globals:
- specifier: ^16.2.0
- version: 16.2.0
+ specifier: ^16.3.0
+ version: 16.3.0
+ nodemon:
+ specifier: ^3.1.10
+ version: 3.1.10
prettier:
- specifier: ^3.5.3
- version: 3.5.3
+ specifier: ^3.6.2
+ version: 3.6.2
prettier-plugin-svelte:
specifier: ^3.4.0
- version: 3.4.0(prettier@3.5.3)(svelte@5.33.18)
+ version: 3.4.0(prettier@3.6.2)(svelte@5.36.14)
prettier-plugin-tailwindcss:
- specifier: ^0.6.12
- version: 0.6.12(prettier-plugin-svelte@3.4.0(prettier@3.5.3)(svelte@5.33.18))(prettier@3.5.3)
+ specifier: ^0.6.14
+ version: 0.6.14(prettier-plugin-svelte@3.4.0(prettier@3.6.2)(svelte@5.36.14))(prettier@3.6.2)
prisma:
- specifier: 6.5.0
- version: 6.5.0(typescript@5.8.3)
+ specifier: 6.12.0
+ version: 6.12.0(typescript@5.8.3)
svelte:
- specifier: ^5.33.18
- version: 5.33.18
+ specifier: ^5.36.14
+ version: 5.36.14
svelte-check:
- specifier: ^4.2.1
- version: 4.2.1(picomatch@4.0.2)(svelte@5.33.18)(typescript@5.8.3)
+ specifier: ^4.3.0
+ version: 4.3.0(picomatch@4.0.2)(svelte@5.36.14)(typescript@5.8.3)
svelte-dnd-action:
- specifier: ^0.9.61
- version: 0.9.61(svelte@5.33.18)
+ specifier: ^0.9.64
+ version: 0.9.64(svelte@5.36.14)
tailwindcss:
- specifier: ^4.1.8
- version: 4.1.8
+ specifier: ^4.1.11
+ version: 4.1.11
typescript:
specifier: ^5.8.3
version: 5.8.3
vite:
- specifier: ^6.3.5
- version: 6.3.5(jiti@2.4.2)(lightningcss@1.30.1)
+ specifier: ^7.0.5
+ version: 7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1)
packages:
@@ -109,6 +169,28 @@ packages:
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
+ '@apidevtools/json-schema-ref-parser@9.1.2':
+ resolution: {integrity: sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==}
+
+ '@apidevtools/openapi-schemas@2.1.0':
+ resolution: {integrity: sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==}
+ engines: {node: '>=10'}
+
+ '@apidevtools/swagger-methods@3.0.2':
+ resolution: {integrity: sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==}
+
+ '@apidevtools/swagger-parser@10.0.3':
+ resolution: {integrity: sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==}
+ peerDependencies:
+ openapi-types: '>=7'
+
+ '@colors/colors@1.6.0':
+ resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==}
+ engines: {node: '>=0.1.90'}
+
+ '@dabh/diagnostics@2.0.3':
+ resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==}
+
'@esbuild/aix-ppc64@0.25.2':
resolution: {integrity: sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==}
engines: {node: '>=18'}
@@ -259,12 +341,6 @@ packages:
cpu: [x64]
os: [win32]
- '@eslint-community/eslint-utils@4.5.1':
- resolution: {integrity: sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- peerDependencies:
- eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
-
'@eslint-community/eslint-utils@4.7.0':
resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -275,33 +351,37 @@ packages:
resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
- '@eslint/compat@1.2.9':
- resolution: {integrity: sha512-gCdSY54n7k+driCadyMNv8JSPzYLeDVM/ikZRtvtROBpRdFSkS8W9A82MqsaY7lZuwL0wiapgD0NT1xT0hyJsA==}
+ '@eslint/compat@1.3.1':
+ resolution: {integrity: sha512-k8MHony59I5EPic6EQTCNOuPoVBnoYXkP+20xvwFjN7t0qI3ImyvyBgg+hIVPwC8JaxVjjUZld+cLfBLFDLucg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
- eslint: ^9.10.0
+ eslint: ^8.40 || 9
peerDependenciesMeta:
eslint:
optional: true
- '@eslint/config-array@0.20.0':
- resolution: {integrity: sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==}
+ '@eslint/config-array@0.21.0':
+ resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@eslint/config-helpers@0.2.1':
- resolution: {integrity: sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==}
+ '@eslint/config-helpers@0.3.0':
+ resolution: {integrity: sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/core@0.14.0':
resolution: {integrity: sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@eslint/core@0.15.1':
+ resolution: {integrity: sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
'@eslint/eslintrc@3.3.1':
resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@eslint/js@9.28.0':
- resolution: {integrity: sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==}
+ '@eslint/js@9.31.0':
+ resolution: {integrity: sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/object-schema@2.1.6':
@@ -354,16 +434,19 @@ packages:
'@jridgewell/trace-mapping@0.3.25':
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
- '@lucide/svelte@0.513.0':
- resolution: {integrity: sha512-XwBQMQkMlr9qp9yVg+epx5MzhBBrqul8atO00y/ZfhlKRJuQZVmq3ELibApqyBtj9ys0Ai4FH/SZcODTUFYXig==}
+ '@jsdevtools/ono@7.1.3':
+ resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==}
+
+ '@lucide/svelte@0.525.0':
+ resolution: {integrity: sha512-dyUxkXzepagLUzL8jHQNdeH286nC66ClLACsg+Neu/bjkRJWPWMzkT+H0DKlE70QdkicGCfs1ZGmXCc351hmZA==}
peerDependencies:
svelte: ^5
'@polka/url@1.0.0-next.29':
resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
- '@prisma/client@6.5.0':
- resolution: {integrity: sha512-M6w1Ql/BeiGoZmhMdAZUXHu5sz5HubyVcKukbLs3l0ELcQb8hTUJxtGEChhv4SVJ0QJlwtLnwOLgIRQhpsm9dw==}
+ '@prisma/client@6.12.0':
+ resolution: {integrity: sha512-wn98bJ3Cj6edlF4jjpgXwbnQIo/fQLqqQHPk2POrZPxTlhY3+n90SSIF3LMRVa8VzRFC/Gec3YKJRxRu+AIGVA==}
engines: {node: '>=18.18'}
peerDependencies:
prisma: '*'
@@ -374,23 +457,23 @@ packages:
typescript:
optional: true
- '@prisma/config@6.5.0':
- resolution: {integrity: sha512-sOH/2Go9Zer67DNFLZk6pYOHj+rumSb0VILgltkoxOjYnlLqUpHPAN826vnx8HigqnOCxj9LRhT6U7uLiIIWgw==}
+ '@prisma/config@6.12.0':
+ resolution: {integrity: sha512-HovZWzhWEMedHxmjefQBRZa40P81N7/+74khKFz9e1AFjakcIQdXgMWKgt20HaACzY+d1LRBC+L4tiz71t9fkg==}
- '@prisma/debug@6.5.0':
- resolution: {integrity: sha512-fc/nusYBlJMzDmDepdUtH9aBsJrda2JNErP9AzuHbgUEQY0/9zQYZdNlXmKoIWENtio+qarPNe/+DQtrX5kMcQ==}
+ '@prisma/debug@6.12.0':
+ resolution: {integrity: sha512-plbz6z72orcqr0eeio7zgUrZj5EudZUpAeWkFTA/DDdXEj28YHDXuiakvR6S7sD6tZi+jiwQEJAPeV6J6m/tEQ==}
- '@prisma/engines-version@6.5.0-73.173f8d54f8d52e692c7e27e72a88314ec7aeff60':
- resolution: {integrity: sha512-iK3EmiVGFDCmXjSpdsKGNqy9hOdLnvYBrJB61far/oP03hlIxrb04OWmDjNTwtmZ3UZdA5MCvI+f+3k2jPTflQ==}
+ '@prisma/engines-version@6.12.0-15.8047c96bbd92db98a2abc7c9323ce77c02c89dbc':
+ resolution: {integrity: sha512-70vhecxBJlRr06VfahDzk9ow4k1HIaSfVUT3X0/kZoHCMl9zbabut4gEXAyzJZxaCGi5igAA7SyyfBI//mmkbQ==}
- '@prisma/engines@6.5.0':
- resolution: {integrity: sha512-FVPQYHgOllJklN9DUyujXvh3hFJCY0NX86sDmBErLvoZjy2OXGiZ5FNf3J/C4/RZZmCypZBYpBKEhx7b7rEsdw==}
+ '@prisma/engines@6.12.0':
+ resolution: {integrity: sha512-4BRZZUaAuB4p0XhTauxelvFs7IllhPmNLvmla0bO1nkECs8n/o1pUvAVbQ/VOrZR5DnF4HED0PrGai+rIOVePA==}
- '@prisma/fetch-engine@6.5.0':
- resolution: {integrity: sha512-3LhYA+FXP6pqY8FLHCjewyE8pGXXJ7BxZw2rhPq+CZAhvflVzq4K8Qly3OrmOkn6wGlz79nyLQdknyCG2HBTuA==}
+ '@prisma/fetch-engine@6.12.0':
+ resolution: {integrity: sha512-EamoiwrK46rpWaEbLX9aqKDPOd8IyLnZAkiYXFNuq0YsU0Z8K09/rH8S7feOWAVJ3xzeSgcEJtBlVDrajM9Sag==}
- '@prisma/get-platform@6.5.0':
- resolution: {integrity: sha512-xYcvyJwNMg2eDptBYFqFLUCfgi+wZLcj6HDMsj0Qw0irvauG4IKmkbywnqwok0B+k+W+p+jThM2DKTSmoPCkzw==}
+ '@prisma/get-platform@6.12.0':
+ resolution: {integrity: sha512-nRerTGhTlgyvcBlyWgt8OLNIV7QgJS2XYXMJD1hysorMCuLAjuDDuoxmVt7C2nLxbuxbWPp7OuFRHC23HqD9dA==}
'@rollup/plugin-commonjs@28.0.3':
resolution: {integrity: sha512-pyltgilam1QPdn+Zd9gaCfOLcnjMEJ9gV+bTw6/r73INdvzf1ah9zLIJBm+kW7R6IUFIQ1YO+VqZtYxZNWFPEQ==}
@@ -433,194 +516,297 @@ packages:
cpu: [arm]
os: [android]
+ '@rollup/rollup-android-arm-eabi@4.45.1':
+ resolution: {integrity: sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==}
+ cpu: [arm]
+ os: [android]
+
'@rollup/rollup-android-arm64@4.39.0':
resolution: {integrity: sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ==}
cpu: [arm64]
os: [android]
+ '@rollup/rollup-android-arm64@4.45.1':
+ resolution: {integrity: sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==}
+ cpu: [arm64]
+ os: [android]
+
'@rollup/rollup-darwin-arm64@4.39.0':
resolution: {integrity: sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q==}
cpu: [arm64]
os: [darwin]
+ '@rollup/rollup-darwin-arm64@4.45.1':
+ resolution: {integrity: sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==}
+ cpu: [arm64]
+ os: [darwin]
+
'@rollup/rollup-darwin-x64@4.39.0':
resolution: {integrity: sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ==}
cpu: [x64]
os: [darwin]
+ '@rollup/rollup-darwin-x64@4.45.1':
+ resolution: {integrity: sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==}
+ cpu: [x64]
+ os: [darwin]
+
'@rollup/rollup-freebsd-arm64@4.39.0':
resolution: {integrity: sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ==}
cpu: [arm64]
os: [freebsd]
+ '@rollup/rollup-freebsd-arm64@4.45.1':
+ resolution: {integrity: sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==}
+ cpu: [arm64]
+ os: [freebsd]
+
'@rollup/rollup-freebsd-x64@4.39.0':
resolution: {integrity: sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q==}
cpu: [x64]
os: [freebsd]
+ '@rollup/rollup-freebsd-x64@4.45.1':
+ resolution: {integrity: sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==}
+ cpu: [x64]
+ os: [freebsd]
+
'@rollup/rollup-linux-arm-gnueabihf@4.39.0':
resolution: {integrity: sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==}
cpu: [arm]
os: [linux]
+ '@rollup/rollup-linux-arm-gnueabihf@4.45.1':
+ resolution: {integrity: sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==}
+ cpu: [arm]
+ os: [linux]
+
'@rollup/rollup-linux-arm-musleabihf@4.39.0':
resolution: {integrity: sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==}
cpu: [arm]
os: [linux]
+ '@rollup/rollup-linux-arm-musleabihf@4.45.1':
+ resolution: {integrity: sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==}
+ cpu: [arm]
+ os: [linux]
+
'@rollup/rollup-linux-arm64-gnu@4.39.0':
resolution: {integrity: sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==}
cpu: [arm64]
os: [linux]
+ '@rollup/rollup-linux-arm64-gnu@4.45.1':
+ resolution: {integrity: sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==}
+ cpu: [arm64]
+ os: [linux]
+
'@rollup/rollup-linux-arm64-musl@4.39.0':
resolution: {integrity: sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==}
cpu: [arm64]
os: [linux]
+ '@rollup/rollup-linux-arm64-musl@4.45.1':
+ resolution: {integrity: sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==}
+ cpu: [arm64]
+ os: [linux]
+
'@rollup/rollup-linux-loongarch64-gnu@4.39.0':
resolution: {integrity: sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==}
cpu: [loong64]
os: [linux]
+ '@rollup/rollup-linux-loongarch64-gnu@4.45.1':
+ resolution: {integrity: sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==}
+ cpu: [loong64]
+ os: [linux]
+
'@rollup/rollup-linux-powerpc64le-gnu@4.39.0':
resolution: {integrity: sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==}
cpu: [ppc64]
os: [linux]
+ '@rollup/rollup-linux-powerpc64le-gnu@4.45.1':
+ resolution: {integrity: sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==}
+ cpu: [ppc64]
+ os: [linux]
+
'@rollup/rollup-linux-riscv64-gnu@4.39.0':
resolution: {integrity: sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==}
cpu: [riscv64]
os: [linux]
+ '@rollup/rollup-linux-riscv64-gnu@4.45.1':
+ resolution: {integrity: sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==}
+ cpu: [riscv64]
+ os: [linux]
+
'@rollup/rollup-linux-riscv64-musl@4.39.0':
resolution: {integrity: sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==}
cpu: [riscv64]
os: [linux]
+ '@rollup/rollup-linux-riscv64-musl@4.45.1':
+ resolution: {integrity: sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==}
+ cpu: [riscv64]
+ os: [linux]
+
'@rollup/rollup-linux-s390x-gnu@4.39.0':
resolution: {integrity: sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==}
cpu: [s390x]
os: [linux]
+ '@rollup/rollup-linux-s390x-gnu@4.45.1':
+ resolution: {integrity: sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==}
+ cpu: [s390x]
+ os: [linux]
+
'@rollup/rollup-linux-x64-gnu@4.39.0':
resolution: {integrity: sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==}
cpu: [x64]
os: [linux]
+ '@rollup/rollup-linux-x64-gnu@4.45.1':
+ resolution: {integrity: sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==}
+ cpu: [x64]
+ os: [linux]
+
'@rollup/rollup-linux-x64-musl@4.39.0':
resolution: {integrity: sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==}
cpu: [x64]
os: [linux]
+ '@rollup/rollup-linux-x64-musl@4.45.1':
+ resolution: {integrity: sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==}
+ cpu: [x64]
+ os: [linux]
+
'@rollup/rollup-win32-arm64-msvc@4.39.0':
resolution: {integrity: sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==}
cpu: [arm64]
os: [win32]
+ '@rollup/rollup-win32-arm64-msvc@4.45.1':
+ resolution: {integrity: sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==}
+ cpu: [arm64]
+ os: [win32]
+
'@rollup/rollup-win32-ia32-msvc@4.39.0':
resolution: {integrity: sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ==}
cpu: [ia32]
os: [win32]
+ '@rollup/rollup-win32-ia32-msvc@4.45.1':
+ resolution: {integrity: sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==}
+ cpu: [ia32]
+ os: [win32]
+
'@rollup/rollup-win32-x64-msvc@4.39.0':
resolution: {integrity: sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug==}
cpu: [x64]
os: [win32]
+ '@rollup/rollup-win32-x64-msvc@4.45.1':
+ resolution: {integrity: sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==}
+ cpu: [x64]
+ os: [win32]
+
+ '@scarf/scarf@1.4.0':
+ resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==}
+
'@sveltejs/acorn-typescript@1.0.5':
resolution: {integrity: sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==}
peerDependencies:
acorn: ^8.9.0
- '@sveltejs/adapter-node@5.2.12':
- resolution: {integrity: sha512-0bp4Yb3jKIEcZWVcJC/L1xXp9zzJS4hDwfb4VITAkfT4OVdkspSHsx7YhqJDbb2hgLl6R9Vs7VQR+fqIVOxPUQ==}
+ '@sveltejs/adapter-node@5.2.13':
+ resolution: {integrity: sha512-yS2TVFmIrxjGhYaV5/iIUrJ3mJl6zjaYn0lBD70vTLnYvJeqf3cjvLXeXCUCuYinhSBoyF4DpfGla49BnIy7sQ==}
peerDependencies:
'@sveltejs/kit': ^2.4.0
- '@sveltejs/kit@2.21.4':
- resolution: {integrity: sha512-683kl4BBnORaYn3vktH01HAHYep8FaiRA21LVY7d6uAX+1D/1gK4WYHRJq90vA01Cz/k6rU3n6vpf4fAn9ipkA==}
+ '@sveltejs/kit@2.25.2':
+ resolution: {integrity: sha512-aKfj82vqEINedoH9Pw4Ip16jj3w8soNq9F3nJqc56kxXW74TcEu/gdTAuLUI+gsl8i+KXfetRqg1F+gG/AZRVQ==}
engines: {node: '>=18.13'}
hasBin: true
peerDependencies:
- '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0
+ '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0
svelte: ^4.0.0 || ^5.0.0-next.0
- vite: ^5.0.3 || ^6.0.0
+ vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0
- '@sveltejs/vite-plugin-svelte-inspector@4.0.1':
- resolution: {integrity: sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==}
- engines: {node: ^18.0.0 || ^20.0.0 || >=22}
+ '@sveltejs/vite-plugin-svelte-inspector@5.0.0':
+ resolution: {integrity: sha512-iwQ8Z4ET6ZFSt/gC+tVfcsSBHwsqc6RumSaiLUkAurW3BCpJam65cmHw0oOlDMTO0u+PZi9hilBRYN+LZNHTUQ==}
+ engines: {node: ^20.19 || ^22.12 || >=24}
peerDependencies:
- '@sveltejs/vite-plugin-svelte': ^5.0.0
+ '@sveltejs/vite-plugin-svelte': ^6.0.0-next.0
svelte: ^5.0.0
- vite: ^6.0.0
+ vite: ^6.3.0 || ^7.0.0
- '@sveltejs/vite-plugin-svelte@5.1.0':
- resolution: {integrity: sha512-wojIS/7GYnJDYIg1higWj2ROA6sSRWvcR1PO/bqEyFr/5UZah26c8Cz4u0NaqjPeVltzsVpt2Tm8d2io0V+4Tw==}
- engines: {node: ^18.0.0 || ^20.0.0 || >=22}
+ '@sveltejs/vite-plugin-svelte@6.1.0':
+ resolution: {integrity: sha512-+U6lz1wvGEG/BvQyL4z/flyNdQ9xDNv5vrh+vWBWTHaebqT0c9RNggpZTo/XSPoHsSCWBlYaTlRX8pZ9GATXCw==}
+ engines: {node: ^20.19 || ^22.12 || >=24}
peerDependencies:
svelte: ^5.0.0
- vite: ^6.0.0
+ vite: ^6.3.0 || ^7.0.0
- '@tailwindcss/node@4.1.8':
- resolution: {integrity: sha512-OWwBsbC9BFAJelmnNcrKuf+bka2ZxCE2A4Ft53Tkg4uoiE67r/PMEYwCsourC26E+kmxfwE0hVzMdxqeW+xu7Q==}
+ '@tailwindcss/node@4.1.11':
+ resolution: {integrity: sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==}
- '@tailwindcss/oxide-android-arm64@4.1.8':
- resolution: {integrity: sha512-Fbz7qni62uKYceWYvUjRqhGfZKwhZDQhlrJKGtnZfuNtHFqa8wmr+Wn74CTWERiW2hn3mN5gTpOoxWKk0jRxjg==}
+ '@tailwindcss/oxide-android-arm64@4.1.11':
+ resolution: {integrity: sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [android]
- '@tailwindcss/oxide-darwin-arm64@4.1.8':
- resolution: {integrity: sha512-RdRvedGsT0vwVVDztvyXhKpsU2ark/BjgG0huo4+2BluxdXo8NDgzl77qh0T1nUxmM11eXwR8jA39ibvSTbi7A==}
+ '@tailwindcss/oxide-darwin-arm64@4.1.11':
+ resolution: {integrity: sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
- '@tailwindcss/oxide-darwin-x64@4.1.8':
- resolution: {integrity: sha512-t6PgxjEMLp5Ovf7uMb2OFmb3kqzVTPPakWpBIFzppk4JE4ix0yEtbtSjPbU8+PZETpaYMtXvss2Sdkx8Vs4XRw==}
+ '@tailwindcss/oxide-darwin-x64@4.1.11':
+ resolution: {integrity: sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
- '@tailwindcss/oxide-freebsd-x64@4.1.8':
- resolution: {integrity: sha512-g8C8eGEyhHTqwPStSwZNSrOlyx0bhK/V/+zX0Y+n7DoRUzyS8eMbVshVOLJTDDC+Qn9IJnilYbIKzpB9n4aBsg==}
+ '@tailwindcss/oxide-freebsd-x64@4.1.11':
+ resolution: {integrity: sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [freebsd]
- '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.8':
- resolution: {integrity: sha512-Jmzr3FA4S2tHhaC6yCjac3rGf7hG9R6Gf2z9i9JFcuyy0u79HfQsh/thifbYTF2ic82KJovKKkIB6Z9TdNhCXQ==}
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11':
+ resolution: {integrity: sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
- '@tailwindcss/oxide-linux-arm64-gnu@4.1.8':
- resolution: {integrity: sha512-qq7jXtO1+UEtCmCeBBIRDrPFIVI4ilEQ97qgBGdwXAARrUqSn/L9fUrkb1XP/mvVtoVeR2bt/0L77xx53bPZ/Q==}
+ '@tailwindcss/oxide-linux-arm64-gnu@4.1.11':
+ resolution: {integrity: sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
- '@tailwindcss/oxide-linux-arm64-musl@4.1.8':
- resolution: {integrity: sha512-O6b8QesPbJCRshsNApsOIpzKt3ztG35gfX9tEf4arD7mwNinsoCKxkj8TgEE0YRjmjtO3r9FlJnT/ENd9EVefQ==}
+ '@tailwindcss/oxide-linux-arm64-musl@4.1.11':
+ resolution: {integrity: sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
- '@tailwindcss/oxide-linux-x64-gnu@4.1.8':
- resolution: {integrity: sha512-32iEXX/pXwikshNOGnERAFwFSfiltmijMIAbUhnNyjFr3tmWmMJWQKU2vNcFX0DACSXJ3ZWcSkzNbaKTdngH6g==}
+ '@tailwindcss/oxide-linux-x64-gnu@4.1.11':
+ resolution: {integrity: sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
- '@tailwindcss/oxide-linux-x64-musl@4.1.8':
- resolution: {integrity: sha512-s+VSSD+TfZeMEsCaFaHTaY5YNj3Dri8rST09gMvYQKwPphacRG7wbuQ5ZJMIJXN/puxPcg/nU+ucvWguPpvBDg==}
+ '@tailwindcss/oxide-linux-x64-musl@4.1.11':
+ resolution: {integrity: sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
- '@tailwindcss/oxide-wasm32-wasi@4.1.8':
- resolution: {integrity: sha512-CXBPVFkpDjM67sS1psWohZ6g/2/cd+cq56vPxK4JeawelxwK4YECgl9Y9TjkE2qfF+9/s1tHHJqrC4SS6cVvSg==}
+ '@tailwindcss/oxide-wasm32-wasi@4.1.11':
+ resolution: {integrity: sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==}
engines: {node: '>=14.0.0'}
cpu: [wasm32]
bundledDependencies:
@@ -631,20 +817,20 @@ packages:
- '@emnapi/wasi-threads'
- tslib
- '@tailwindcss/oxide-win32-arm64-msvc@4.1.8':
- resolution: {integrity: sha512-7GmYk1n28teDHUjPlIx4Z6Z4hHEgvP5ZW2QS9ygnDAdI/myh3HTHjDqtSqgu1BpRoI4OiLx+fThAyA1JePoENA==}
+ '@tailwindcss/oxide-win32-arm64-msvc@4.1.11':
+ resolution: {integrity: sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
- '@tailwindcss/oxide-win32-x64-msvc@4.1.8':
- resolution: {integrity: sha512-fou+U20j+Jl0EHwK92spoWISON2OBnCazIc038Xj2TdweYV33ZRkS9nwqiUi2d/Wba5xg5UoHfvynnb/UB49cQ==}
+ '@tailwindcss/oxide-win32-x64-msvc@4.1.11':
+ resolution: {integrity: sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
- '@tailwindcss/oxide@4.1.8':
- resolution: {integrity: sha512-d7qvv9PsM5N3VNKhwVUhpK6r4h9wtLkJ6lz9ZY9aeZgrUWk1Z8VPyqyDT9MZlem7GTGseRQHkeB1j3tC7W1P+A==}
+ '@tailwindcss/oxide@4.1.11':
+ resolution: {integrity: sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==}
engines: {node: '>= 10'}
'@tailwindcss/typography@0.5.16':
@@ -652,23 +838,88 @@ packages:
peerDependencies:
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
- '@tailwindcss/vite@4.1.8':
- resolution: {integrity: sha512-CQ+I8yxNV5/6uGaJjiuymgw0kEQiNKRinYbZXPdx1fk5WgiyReG0VaUx/Xq6aVNSUNJFzxm6o8FNKS5aMaim5A==}
+ '@tailwindcss/vite@4.1.11':
+ resolution: {integrity: sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw==}
peerDependencies:
- vite: ^5.2.0 || ^6
+ vite: ^5.2.0 || ^6 || ^7
+
+ '@types/bcryptjs@3.0.0':
+ resolution: {integrity: sha512-WRZOuCuaz8UcZZE4R5HXTco2goQSI2XxjGY3hbM/xDvwmqFWd4ivooImsMx65OKM6CtNKbnZ5YL+YwAwK7c1dg==}
+ deprecated: This is a stub types definition. bcryptjs provides its own type definitions, so you do not need this installed.
+
+ '@types/body-parser@1.19.6':
+ resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==}
+
+ '@types/connect@3.4.38':
+ resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
'@types/cookie@0.6.0':
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
+ '@types/cors@2.8.19':
+ resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==}
+
'@types/estree@1.0.7':
resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
+ '@types/estree@1.0.8':
+ resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
+
+ '@types/express-serve-static-core@5.0.7':
+ resolution: {integrity: sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==}
+
+ '@types/express@5.0.3':
+ resolution: {integrity: sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==}
+
+ '@types/http-errors@2.0.5':
+ resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==}
+
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+ '@types/jsonwebtoken@9.0.10':
+ resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==}
+
+ '@types/mime@1.3.5':
+ resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
+
+ '@types/morgan@1.9.10':
+ resolution: {integrity: sha512-sS4A1zheMvsADRVfT0lYbJ4S9lmsey8Zo2F7cnbYjWHP67Q0AwMYuuzLlkIM2N8gAbb9cubhIVFwcIN2XyYCkA==}
+
+ '@types/ms@2.1.0':
+ resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
+
+ '@types/node@24.1.0':
+ resolution: {integrity: sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==}
+
+ '@types/qs@6.14.0':
+ resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==}
+
+ '@types/range-parser@1.2.7':
+ resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
+
'@types/resolve@1.20.2':
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
+ '@types/send@0.17.5':
+ resolution: {integrity: sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==}
+
+ '@types/serve-static@1.15.8':
+ resolution: {integrity: sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==}
+
+ '@types/swagger-jsdoc@6.0.4':
+ resolution: {integrity: sha512-W+Xw5epcOZrF/AooUM/PccNMSAFOKWZA5dasNyMujTwsBkU74njSJBpvCCJhHAJ95XRMzQrrW844Btu0uoetwQ==}
+
+ '@types/swagger-ui-express@4.1.8':
+ resolution: {integrity: sha512-AhZV8/EIreHFmBV5wAs0gzJUNq9JbbSXgJLQubCC0jtIo6prnI9MIRRxnU4MZX9RB9yXxF1V4R7jtLl/Wcj31g==}
+
+ '@types/triple-beam@1.3.5':
+ resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==}
+
+ accepts@2.0.0:
+ resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
+ engines: {node: '>= 0.6'}
+
acorn-jsx@5.3.2:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
@@ -679,6 +930,15 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
+ acorn@8.15.0:
+ resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+
+ agent-base@7.1.4:
+ resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
+ engines: {node: '>= 14'}
+
ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
@@ -686,6 +946,10 @@ packages:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
+ anymatch@3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+ engines: {node: '>= 8'}
+
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
@@ -693,11 +957,14 @@ packages:
resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
engines: {node: '>= 0.4'}
+ async@3.2.6:
+ resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
+
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
- axios@1.9.0:
- resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==}
+ axios@1.11.0:
+ resolution: {integrity: sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==}
axobject-query@4.1.0:
resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
@@ -706,13 +973,53 @@ packages:
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+ base64-js@1.5.1:
+ resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+
+ basic-auth@2.0.1:
+ resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==}
+ engines: {node: '>= 0.8'}
+
+ bcryptjs@3.0.2:
+ resolution: {integrity: sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==}
+ hasBin: true
+
+ bignumber.js@9.3.1:
+ resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==}
+
+ binary-extensions@2.3.0:
+ resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
+ engines: {node: '>=8'}
+
+ body-parser@2.2.0:
+ resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==}
+ engines: {node: '>=18'}
+
brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
+ buffer-equal-constant-time@1.0.1:
+ resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
+
+ bytes@3.1.2:
+ resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
+ engines: {node: '>= 0.8'}
+
call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
+ call-bound@1.0.4:
+ resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
+ engines: {node: '>= 0.4'}
+
+ call-me-maybe@1.0.2:
+ resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==}
+
callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
@@ -721,6 +1028,10 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
+ chokidar@3.6.0:
+ resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
+ engines: {node: '>= 8.10.0'}
+
chokidar@4.0.3:
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
engines: {node: '>= 14.16.0'}
@@ -733,27 +1044,70 @@ packages:
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
engines: {node: '>=6'}
+ color-convert@1.9.3:
+ resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
+
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
+ color-name@1.1.3:
+ resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
+
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+ color-string@1.9.1:
+ resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
+
+ color@3.2.1:
+ resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==}
+
+ colorspace@1.1.4:
+ resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==}
+
combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
+ commander@6.2.0:
+ resolution: {integrity: sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==}
+ engines: {node: '>= 6'}
+
+ commander@9.5.0:
+ resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
+ engines: {node: ^12.20.0 || >=14}
+
commondir@1.0.1:
resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+ content-disposition@1.0.0:
+ resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==}
+ engines: {node: '>= 0.6'}
+
+ content-type@1.0.5:
+ resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
+ engines: {node: '>= 0.6'}
+
+ cookie-signature@1.2.2:
+ resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==}
+ engines: {node: '>=6.6.0'}
+
cookie@0.6.0:
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
engines: {node: '>= 0.6'}
+ cookie@0.7.2:
+ resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
+ engines: {node: '>= 0.6'}
+
+ cors@2.8.5:
+ resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
+ engines: {node: '>= 0.10'}
+
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
@@ -763,12 +1117,15 @@ packages:
engines: {node: '>=4'}
hasBin: true
+ data-uri-to-buffer@4.0.1:
+ resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
+ engines: {node: '>= 12'}
+
date-fns@4.1.0:
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
- debug@4.4.0:
- resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
- engines: {node: '>=6.0'}
+ debug@2.6.9:
+ resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
@@ -795,9 +1152,9 @@ packages:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
- detect-libc@2.0.3:
- resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
- engines: {node: '>=8'}
+ depd@2.0.0:
+ resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
+ engines: {node: '>= 0.8'}
detect-libc@2.0.4:
resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
@@ -806,10 +1163,31 @@ packages:
devalue@5.1.1:
resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==}
+ doctrine@3.0.0:
+ resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
+ engines: {node: '>=6.0.0'}
+
+ dotenv@17.2.1:
+ resolution: {integrity: sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==}
+ engines: {node: '>=12'}
+
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
+ ecdsa-sig-formatter@1.0.11:
+ resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
+
+ ee-first@1.1.1:
+ resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
+
+ enabled@2.0.0:
+ resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==}
+
+ encodeurl@2.0.0:
+ resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
+ engines: {node: '>= 0.8'}
+
enhanced-resolve@5.18.1:
resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==}
engines: {node: '>=10.13.0'}
@@ -830,28 +1208,26 @@ packages:
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
engines: {node: '>= 0.4'}
- esbuild-register@3.6.0:
- resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==}
- peerDependencies:
- esbuild: '>=0.12 <1'
-
esbuild@0.25.2:
resolution: {integrity: sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==}
engines: {node: '>=18'}
hasBin: true
+ escape-html@1.0.3:
+ resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
+
escape-string-regexp@4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
- eslint-config-prettier@10.1.5:
- resolution: {integrity: sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==}
+ eslint-config-prettier@10.1.8:
+ resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==}
hasBin: true
peerDependencies:
eslint: '>=7.0.0'
- eslint-plugin-svelte@3.9.2:
- resolution: {integrity: sha512-aqzfHtG9RPaFhCUFm5QFC6eFY/yHFQIT8VYYFe7/mT2A9mbgVR3XV2keCqU19LN8iVD9mdvRvqHU+4+CzJImvg==}
+ eslint-plugin-svelte@3.11.0:
+ resolution: {integrity: sha512-KliWlkieHyEa65aQIkRwUFfHzT5Cn4u3BQQsu3KlkJOs7c1u7ryn84EWaOjEzilbKgttT4OfBURA8Uc4JBSQIw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.1 || ^9.0.0
@@ -864,6 +1240,10 @@ packages:
resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ eslint-scope@8.4.0:
+ resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
eslint-visitor-keys@3.4.3:
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -872,8 +1252,12 @@ packages:
resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- eslint@9.28.0:
- resolution: {integrity: sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==}
+ eslint-visitor-keys@4.2.1:
+ resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ eslint@9.31.0:
+ resolution: {integrity: sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
hasBin: true
peerDependencies:
@@ -889,12 +1273,16 @@ packages:
resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ espree@10.4.0:
+ resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
esquery@1.6.0:
resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
engines: {node: '>=0.10'}
- esrap@1.4.9:
- resolution: {integrity: sha512-3OMlcd0a03UGuZpPeUC1HxR3nA23l+HEyCiZw3b3FumJIN9KphoGzDJKMXI1S72jVS1dsenDyQC0kJlO1U9E1g==}
+ esrap@2.1.0:
+ resolution: {integrity: sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA==}
esrecurse@4.3.0:
resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
@@ -911,6 +1299,23 @@ packages:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
+ etag@1.8.1:
+ resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
+ engines: {node: '>= 0.6'}
+
+ express-rate-limit@8.0.1:
+ resolution: {integrity: sha512-aZVCnybn7TVmxO4BtlmnvX+nuz8qHW124KKJ8dumsBsmv5ZLxE0pYu7S2nwyRBGHHCAzdmnGyrc5U/rksSPO7Q==}
+ engines: {node: '>= 16'}
+ peerDependencies:
+ express: '>= 4.11'
+
+ express@5.1.0:
+ resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==}
+ engines: {node: '>= 18'}
+
+ extend@3.0.2:
+ resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
+
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
@@ -920,14 +1325,6 @@ packages:
fast-levenshtein@2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
- fdir@6.4.3:
- resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==}
- peerDependencies:
- picomatch: ^3 || ^4
- peerDependenciesMeta:
- picomatch:
- optional: true
-
fdir@6.4.6:
resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==}
peerDependencies:
@@ -936,10 +1333,25 @@ packages:
picomatch:
optional: true
+ fecha@4.2.3:
+ resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==}
+
+ fetch-blob@3.2.0:
+ resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
+ engines: {node: ^12.20 || >= 14.13}
+
file-entry-cache@8.0.0:
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
engines: {node: '>=16.0.0'}
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ finalhandler@2.1.0:
+ resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==}
+ engines: {node: '>= 0.8'}
+
find-up@5.0.0:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
@@ -951,6 +1363,9 @@ packages:
flatted@3.3.3:
resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
+ fn.name@1.1.0:
+ resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==}
+
follow-redirects@1.15.9:
resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
engines: {node: '>=4.0'}
@@ -960,10 +1375,25 @@ packages:
debug:
optional: true
- form-data@4.0.2:
- resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==}
+ form-data@4.0.4:
+ resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==}
engines: {node: '>= 6'}
+ formdata-polyfill@4.0.10:
+ resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
+ engines: {node: '>=12.20.0'}
+
+ forwarded@0.2.0:
+ resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
+ engines: {node: '>= 0.6'}
+
+ fresh@2.0.0:
+ resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
+ engines: {node: '>= 0.8'}
+
+ fs.realpath@1.0.0:
+ resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@@ -972,6 +1402,14 @@ packages:
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+ gaxios@7.1.1:
+ resolution: {integrity: sha512-Odju3uBUJyVCkW64nLD4wKLhbh93bh6vIg/ZIXkWiLPBrdgtc65+tls/qml+un3pr6JqYVFDZbbmLDQT68rTOQ==}
+ engines: {node: '>=18'}
+
+ gcp-metadata@7.0.1:
+ resolution: {integrity: sha512-UcO3kefx6dCcZkgcTGgVOTFb7b1LlQ02hY1omMjjrrBzkajRMCFgYOjs7J71WqnuG1k2b+9ppGL7FsOfhZMQKQ==}
+ engines: {node: '>=18'}
+
get-intrinsic@1.3.0:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'}
@@ -980,18 +1418,34 @@ packages:
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
engines: {node: '>= 0.4'}
+ glob-parent@5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+
glob-parent@6.0.2:
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
engines: {node: '>=10.13.0'}
+ glob@7.1.6:
+ resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==}
+ deprecated: Glob versions prior to v9 are no longer supported
+
globals@14.0.0:
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
engines: {node: '>=18'}
- globals@16.2.0:
- resolution: {integrity: sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==}
+ globals@16.3.0:
+ resolution: {integrity: sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==}
engines: {node: '>=18'}
+ google-auth-library@10.2.0:
+ resolution: {integrity: sha512-gy/0hRx8+Ye0HlUm3GrfpR4lbmJQ6bJ7F44DmN7GtMxxzWSojLzx0Bhv/hj7Wlj7a2On0FcT8jrz8Y1c1nxCyg==}
+ engines: {node: '>=18'}
+
+ google-logging-utils@1.1.1:
+ resolution: {integrity: sha512-rcX58I7nqpu4mbKztFeOAObbomBbHU2oIb/d3tJfF3dizGSApqtSwYJigGCooHdnMyQBIw8BrWyK96w3YXgr6A==}
+ engines: {node: '>=14'}
+
gopd@1.2.0:
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
engines: {node: '>= 0.4'}
@@ -999,6 +1453,14 @@ packages:
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+ gtoken@8.0.0:
+ resolution: {integrity: sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==}
+ engines: {node: '>=18'}
+
+ has-flag@3.0.0:
+ resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
+ engines: {node: '>=4'}
+
has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
@@ -1015,10 +1477,29 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
+ helmet@8.1.0:
+ resolution: {integrity: sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg==}
+ engines: {node: '>=18.0.0'}
+
highlight.js@11.11.1:
resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==}
engines: {node: '>=12.0.0'}
+ http-errors@2.0.0:
+ resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
+ engines: {node: '>= 0.8'}
+
+ https-proxy-agent@7.0.6:
+ resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
+ engines: {node: '>= 14'}
+
+ iconv-lite@0.6.3:
+ resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+ engines: {node: '>=0.10.0'}
+
+ ignore-by-default@1.0.1:
+ resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
+
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@@ -1031,6 +1512,28 @@ packages:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
+ inflight@1.0.6:
+ resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+ deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
+
+ inherits@2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+
+ ip-address@10.0.1:
+ resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==}
+ engines: {node: '>= 12'}
+
+ ipaddr.js@1.9.1:
+ resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
+ engines: {node: '>= 0.10'}
+
+ is-arrayish@0.3.2:
+ resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
+
+ is-binary-path@2.1.0:
+ resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+ engines: {node: '>=8'}
+
is-core-module@2.16.1:
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
engines: {node: '>= 0.4'}
@@ -1046,12 +1549,23 @@ packages:
is-module@1.0.0:
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ is-promise@4.0.0:
+ resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
+
is-reference@1.2.1:
resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}
is-reference@3.0.3:
resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==}
+ is-stream@2.0.1:
+ resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
+ engines: {node: '>=8'}
+
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
@@ -1063,6 +1577,9 @@ packages:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
+ json-bigint@1.0.0:
+ resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==}
+
json-buffer@3.0.1:
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
@@ -1072,6 +1589,22 @@ packages:
json-stable-stringify-without-jsonify@1.0.1:
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+ jsonwebtoken@9.0.2:
+ resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==}
+ engines: {node: '>=12', npm: '>=6'}
+
+ jwa@1.4.2:
+ resolution: {integrity: sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==}
+
+ jwa@2.0.1:
+ resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==}
+
+ jws@3.2.2:
+ resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==}
+
+ jws@4.0.0:
+ resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==}
+
keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
@@ -1079,15 +1612,18 @@ packages:
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
engines: {node: '>=6'}
- known-css-properties@0.36.0:
- resolution: {integrity: sha512-A+9jP+IUmuQsNdsLdcg6Yt7voiMF/D4K83ew0OpJtpu+l34ef7LaohWV0Rc6KNvzw6ZDizkqfyB5JznZnzuKQA==}
+ known-css-properties@0.37.0:
+ resolution: {integrity: sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==}
+
+ kuler@2.0.0:
+ resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==}
levn@0.4.1:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
- libphonenumber-js@1.12.9:
- resolution: {integrity: sha512-VWwAdNeJgN7jFOD+wN4qx83DTPMVPPAUyx9/TUkBXKLiNkuWWk6anV0439tgdtwaJDrEdqkvdN22iA6J4bUCZg==}
+ libphonenumber-js@1.12.10:
+ resolution: {integrity: sha512-E91vHJD61jekHHR/RF/E83T/CMoaLXT7cwYA75T4gim4FZjnM6hbJjVIGg7chqlSqRsSvQ3izGmOjHy1SQzcGQ==}
lightningcss-darwin-arm64@1.30.1:
resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==}
@@ -1167,32 +1703,81 @@ packages:
lodash.castarray@4.4.0:
resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
+ lodash.get@4.4.2:
+ resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
+ deprecated: This package is deprecated. Use the optional chaining (?.) operator instead.
+
+ lodash.includes@4.3.0:
+ resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==}
+
+ lodash.isboolean@3.0.3:
+ resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
+
+ lodash.isequal@4.5.0:
+ resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
+ deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead.
+
+ lodash.isinteger@4.0.4:
+ resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==}
+
+ lodash.isnumber@3.0.3:
+ resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==}
+
lodash.isplainobject@4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
+ lodash.isstring@4.0.1:
+ resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==}
+
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+ lodash.mergewith@4.6.2:
+ resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==}
+
+ lodash.once@4.1.1:
+ resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
+
+ logform@2.7.0:
+ resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==}
+ engines: {node: '>= 12.0.0'}
+
magic-string@0.30.17:
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
- marked@15.0.12:
- resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==}
- engines: {node: '>= 18'}
+ marked@16.1.1:
+ resolution: {integrity: sha512-ij/2lXfCRT71L6u0M29tJPhP0bM5shLL3u5BePhFwPELj2blMJ6GDtD7PfJhRLhJ/c2UwrK17ySVcDzy2YHjHQ==}
+ engines: {node: '>= 20'}
hasBin: true
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
+ media-typer@1.1.0:
+ resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==}
+ engines: {node: '>= 0.8'}
+
+ merge-descriptors@2.0.0:
+ resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==}
+ engines: {node: '>=18'}
+
mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
+ mime-db@1.54.0:
+ resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
+ engines: {node: '>= 0.6'}
+
mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
+ mime-types@3.0.1:
+ resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==}
+ engines: {node: '>= 0.6'}
+
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
@@ -1209,6 +1794,10 @@ packages:
engines: {node: '>=10'}
hasBin: true
+ morgan@1.10.1:
+ resolution: {integrity: sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==}
+ engines: {node: '>= 0.8.0'}
+
mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
@@ -1217,6 +1806,9 @@ packages:
resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
engines: {node: '>=10'}
+ ms@2.0.0:
+ resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
+
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -1228,6 +1820,57 @@ packages:
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ negotiator@1.0.0:
+ resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
+ engines: {node: '>= 0.6'}
+
+ node-domexception@1.0.0:
+ resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
+ engines: {node: '>=10.5.0'}
+ deprecated: Use your platform's native DOMException instead
+
+ node-fetch@3.3.2:
+ resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+ nodemon@3.1.10:
+ resolution: {integrity: sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ normalize-path@3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+
+ object-assign@4.1.1:
+ resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
+ engines: {node: '>=0.10.0'}
+
+ object-inspect@1.13.4:
+ resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
+ engines: {node: '>= 0.4'}
+
+ on-finished@2.3.0:
+ resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==}
+ engines: {node: '>= 0.8'}
+
+ on-finished@2.4.1:
+ resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
+ engines: {node: '>= 0.8'}
+
+ on-headers@1.1.0:
+ resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==}
+ engines: {node: '>= 0.8'}
+
+ once@1.4.0:
+ resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+
+ one-time@1.0.0:
+ resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==}
+
+ openapi-types@12.1.3:
+ resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==}
+
optionator@0.9.4:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'}
@@ -1244,10 +1887,18 @@ packages:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
+ parseurl@1.3.3:
+ resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
+ engines: {node: '>= 0.8'}
+
path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
+ path-is-absolute@1.0.1:
+ resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
+ engines: {node: '>=0.10.0'}
+
path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
@@ -1255,9 +1906,17 @@ packages:
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+ path-to-regexp@8.2.0:
+ resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==}
+ engines: {node: '>=16'}
+
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
picomatch@4.0.2:
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
engines: {node: '>=12'}
@@ -1298,6 +1957,10 @@ packages:
resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
engines: {node: ^10 || ^12 || >=14}
+ postcss@8.5.6:
+ resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
+ engines: {node: ^10 || ^12 || >=14}
+
prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
@@ -1308,11 +1971,13 @@ packages:
prettier: ^3.0.0
svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0
- prettier-plugin-tailwindcss@0.6.12:
- resolution: {integrity: sha512-OuTQKoqNwV7RnxTPwXWzOFXy6Jc4z8oeRZYGuMpRyG3WbuR3jjXdQFK8qFBMBx8UHWdHrddARz2fgUenild6aw==}
+ prettier-plugin-tailwindcss@0.6.14:
+ resolution: {integrity: sha512-pi2e/+ZygeIqntN+vC573BcW5Cve8zUB0SSAGxqpB4f96boZF4M3phPVoOFCeypwkpRYdi7+jQ5YJJUwrkGUAg==}
engines: {node: '>=14.21.3'}
peerDependencies:
'@ianvs/prettier-plugin-sort-imports': '*'
+ '@prettier/plugin-hermes': '*'
+ '@prettier/plugin-oxc': '*'
'@prettier/plugin-pug': '*'
'@shopify/prettier-plugin-liquid': '*'
'@trivago/prettier-plugin-sort-imports': '*'
@@ -1332,6 +1997,10 @@ packages:
peerDependenciesMeta:
'@ianvs/prettier-plugin-sort-imports':
optional: true
+ '@prettier/plugin-hermes':
+ optional: true
+ '@prettier/plugin-oxc':
+ optional: true
'@prettier/plugin-pug':
optional: true
'@shopify/prettier-plugin-liquid':
@@ -1363,13 +2032,13 @@ packages:
prettier-plugin-svelte:
optional: true
- prettier@3.5.3:
- resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
+ prettier@3.6.2:
+ resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
engines: {node: '>=14'}
hasBin: true
- prisma@6.5.0:
- resolution: {integrity: sha512-yUGXmWqv5F4PByMSNbYFxke/WbnyTLjnJ5bKr8fLkcnY7U5rU9rUTh/+Fja+gOrRxEgtCbCtca94IeITj4j/pg==}
+ prisma@6.12.0:
+ resolution: {integrity: sha512-pmV7NEqQej9WjizN6RSNIwf7Y+jeh9mY1JEX2WjGxJi4YZWexClhde1yz/FuvAM+cTwzchcMytu2m4I6wPkIzg==}
engines: {node: '>=18.18'}
hasBin: true
peerDependencies:
@@ -1378,13 +2047,40 @@ packages:
typescript:
optional: true
+ proxy-addr@2.0.7:
+ resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
+ engines: {node: '>= 0.10'}
+
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+ pstree.remy@1.1.8:
+ resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==}
+
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
+ qs@6.14.0:
+ resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
+ engines: {node: '>=0.6'}
+
+ range-parser@1.2.1:
+ resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
+ engines: {node: '>= 0.6'}
+
+ raw-body@3.0.0:
+ resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==}
+ engines: {node: '>= 0.8'}
+
+ readable-stream@3.6.2:
+ resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
+ engines: {node: '>= 6'}
+
+ readdirp@3.6.0:
+ resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+ engines: {node: '>=8.10.0'}
+
readdirp@4.1.2:
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
engines: {node: '>= 14.18.0'}
@@ -1403,10 +2099,32 @@ packages:
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
+ rollup@4.45.1:
+ resolution: {integrity: sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+
+ router@2.2.0:
+ resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
+ engines: {node: '>= 18'}
+
sade@1.8.1:
resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
engines: {node: '>=6'}
+ safe-buffer@5.1.2:
+ resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
+
+ safe-buffer@5.2.1:
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+
+ safe-stable-stringify@2.5.0:
+ resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==}
+ engines: {node: '>=10'}
+
+ safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
schema-dts@1.1.5:
resolution: {integrity: sha512-RJr9EaCmsLzBX2NDiO5Z3ux2BVosNZN5jo0gWgsyKvxKIUL5R3swNvoorulAeL9kLB0iTSX7V6aokhla2m7xbg==}
@@ -1415,9 +2133,20 @@ packages:
engines: {node: '>=10'}
hasBin: true
+ send@1.2.0:
+ resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==}
+ engines: {node: '>= 18'}
+
+ serve-static@2.2.0:
+ resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==}
+ engines: {node: '>= 18'}
+
set-cookie-parser@2.7.1:
resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
+ setprototypeof@1.2.0:
+ resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+
shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
@@ -1426,6 +2155,29 @@ packages:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
+ side-channel-list@1.0.0:
+ resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
+ engines: {node: '>= 0.4'}
+
+ side-channel-map@1.0.1:
+ resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
+ engines: {node: '>= 0.4'}
+
+ side-channel-weakmap@1.0.2:
+ resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
+ engines: {node: '>= 0.4'}
+
+ side-channel@1.1.0:
+ resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
+ engines: {node: '>= 0.4'}
+
+ simple-swizzle@0.2.2:
+ resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
+
+ simple-update-notifier@2.0.0:
+ resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
+ engines: {node: '>=10'}
+
sirv@3.0.1:
resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==}
engines: {node: '>=18'}
@@ -1434,10 +2186,28 @@ packages:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
+ stack-trace@0.0.10:
+ resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==}
+
+ statuses@2.0.1:
+ resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
+ engines: {node: '>= 0.8'}
+
+ statuses@2.0.2:
+ resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
+ engines: {node: '>= 0.8'}
+
+ string_decoder@1.3.0:
+ resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+
strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
+ supports-color@5.5.0:
+ resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
+ engines: {node: '>=4'}
+
supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
@@ -1446,21 +2216,21 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
- svelte-check@4.2.1:
- resolution: {integrity: sha512-e49SU1RStvQhoipkQ/aonDhHnG3qxHSBtNfBRb9pxVXoa+N7qybAo32KgA9wEb2PCYFNaDg7bZCdhLD1vHpdYA==}
+ svelte-check@4.3.0:
+ resolution: {integrity: sha512-Iz8dFXzBNAM7XlEIsUjUGQhbEE+Pvv9odb9+0+ITTgFWZBGeJRRYqHUUglwe2EkLD5LIsQaAc4IUJyvtKuOO5w==}
engines: {node: '>= 18.0.0'}
hasBin: true
peerDependencies:
svelte: ^4.0.0 || ^5.0.0-next.0
typescript: '>=5.0.0'
- svelte-dnd-action@0.9.61:
- resolution: {integrity: sha512-xj0jZNdV44MAMbdGIAuBYEombmK7A7ticemOtdR5ErWw0f3IxcfcnrRjlYEK0rRjsahVsU+VdGUMwjPVyXrSrA==}
+ svelte-dnd-action@0.9.64:
+ resolution: {integrity: sha512-kbbnOTuVc+VINheraVyEQ7K11jXdQii6JNTGpsyIuwUqmda030eT3rPpqckD8UVh1DuyYH3xqyJDTWb8S610Jg==}
peerDependencies:
svelte: '>=3.23.0 || ^5.0.0-next.0'
- svelte-eslint-parser@1.2.0:
- resolution: {integrity: sha512-mbPtajIeuiyU80BEyGvwAktBeTX7KCr5/0l+uRGLq1dafwRNrjfM5kHGJScEBlPG3ipu6dJqfW/k0/fujvIEVw==}
+ svelte-eslint-parser@1.3.0:
+ resolution: {integrity: sha512-VCgMHKV7UtOGcGLGNFSbmdm6kEKjtzo5nnpGU/mnx4OsFY6bZ7QwRF5DUx+Hokw5Lvdyo8dpk8B1m8mliomrNg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
svelte: ^3.37.0 || ^4.0.0 || ^5.0.0
@@ -1476,12 +2246,30 @@ packages:
peerDependencies:
svelte: ^5.0.0
- svelte@5.33.18:
- resolution: {integrity: sha512-GVAhi8vi8pGne/wlEdnfWIJvSR9eKvEknxjfL5Sr8gQALiyk8Ey+H0lhUYLpjW+MrqgH9h4dgh2NF6/BTFprRg==}
+ svelte@5.36.14:
+ resolution: {integrity: sha512-okgNwfVa4FfDGOgd0ndooKjQz1LknUFDGfEJp6QNjYP6B4hDG0KktOP+Pta3ZtE8s+JELsYP+7nqMrJzQLkf5A==}
engines: {node: '>=18'}
- tailwindcss@4.1.8:
- resolution: {integrity: sha512-kjeW8gjdxasbmFKpVGrGd5T4i40mV5J2Rasw48QARfYeQ8YS9x02ON9SFWax3Qf616rt4Cp3nVNIj6Hd1mP3og==}
+ swagger-jsdoc@6.2.8:
+ resolution: {integrity: sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==}
+ engines: {node: '>=12.0.0'}
+ hasBin: true
+
+ swagger-parser@10.0.3:
+ resolution: {integrity: sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==}
+ engines: {node: '>=10'}
+
+ swagger-ui-dist@5.27.0:
+ resolution: {integrity: sha512-tS6LRyBhY6yAqxrfsA9IYpGWPUJOri6sclySa7TdC7XQfGLvTwDY531KLgfQwHEtQsn+sT4JlUspbeQDBVGWig==}
+
+ swagger-ui-express@5.0.1:
+ resolution: {integrity: sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==}
+ engines: {node: '>= v0.10.32'}
+ peerDependencies:
+ express: '>=4.0.0 || >=5.0.0-beta'
+
+ tailwindcss@4.1.11:
+ resolution: {integrity: sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==}
tapable@2.2.1:
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
@@ -1491,23 +2279,56 @@ packages:
resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==}
engines: {node: '>=18'}
+ text-hex@1.0.0:
+ resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==}
+
tinyglobby@0.2.14:
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
engines: {node: '>=12.0.0'}
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
+ toidentifier@1.0.1:
+ resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
+ engines: {node: '>=0.6'}
+
totalist@3.0.1:
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
engines: {node: '>=6'}
+ touch@3.1.1:
+ resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==}
+ hasBin: true
+
+ triple-beam@1.4.1:
+ resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==}
+ engines: {node: '>= 14.0.0'}
+
type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
+ type-is@2.0.1:
+ resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
+ engines: {node: '>= 0.6'}
+
typescript@5.8.3:
resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
engines: {node: '>=14.17'}
hasBin: true
+ undefsafe@2.0.5:
+ resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==}
+
+ undici-types@7.8.0:
+ resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==}
+
+ unpipe@1.0.0:
+ resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
+ engines: {node: '>= 0.8'}
+
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
@@ -1518,19 +2339,27 @@ packages:
resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==}
hasBin: true
- vite@6.3.5:
- resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==}
- engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ validator@13.15.15:
+ resolution: {integrity: sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A==}
+ engines: {node: '>= 0.10'}
+
+ vary@1.1.2:
+ resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
+ engines: {node: '>= 0.8'}
+
+ vite@7.0.5:
+ resolution: {integrity: sha512-1mncVwJxy2C9ThLwz0+2GKZyEXuC3MyWtAAlNftlZZXZDP3AJt5FmwcMit/IGGaNZ8ZOB2BNO/HFUB+CpN0NQw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
peerDependencies:
- '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+ '@types/node': ^20.19.0 || >=22.12.0
jiti: '>=1.21.0'
- less: '*'
+ less: ^4.0.0
lightningcss: ^1.21.0
- sass: '*'
- sass-embedded: '*'
- stylus: '*'
- sugarss: '*'
+ sass: ^1.70.0
+ sass-embedded: ^1.70.0
+ stylus: '>=0.54.8'
+ sugarss: ^5.0.0
terser: ^5.16.0
tsx: ^4.8.1
yaml: ^2.4.2
@@ -1558,23 +2387,38 @@ packages:
yaml:
optional: true
- vitefu@1.0.6:
- resolution: {integrity: sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA==}
+ vitefu@1.1.1:
+ resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==}
peerDependencies:
- vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0
+ vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0
peerDependenciesMeta:
vite:
optional: true
+ web-streams-polyfill@3.3.3:
+ resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
+ engines: {node: '>= 8'}
+
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
hasBin: true
+ winston-transport@4.9.0:
+ resolution: {integrity: sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==}
+ engines: {node: '>= 12.0.0'}
+
+ winston@3.17.0:
+ resolution: {integrity: sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==}
+ engines: {node: '>= 12.0.0'}
+
word-wrap@1.2.5:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'}
+ wrappy@1.0.2:
+ resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+
yallist@5.0.0:
resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
engines: {node: '>=18'}
@@ -1583,15 +2427,24 @@ packages:
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
engines: {node: '>= 6'}
+ yaml@2.0.0-1:
+ resolution: {integrity: sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==}
+ engines: {node: '>= 6'}
+
yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
+ z-schema@5.0.5:
+ resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==}
+ engines: {node: '>=8.0.0'}
+ hasBin: true
+
zimmerframe@1.1.2:
resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==}
- zod@3.25.57:
- resolution: {integrity: sha512-6tgzLuwVST5oLUxXTmBqoinKMd3JeesgbgseXeFasKKj8Q1FCZrHnbqJOyiEvr4cVAlbug+CgIsmJ8cl/pU5FA==}
+ zod@4.0.8:
+ resolution: {integrity: sha512-+MSh9cZU9r3QKlHqrgHMTSr3QwMGv4PLfR0M4N/sYWV5/x67HgXEhIGObdBkpnX8G78pTgWnIrBL2lZcNJOtfg==}
snapshots:
@@ -1600,6 +2453,35 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.8
'@jridgewell/trace-mapping': 0.3.25
+ '@apidevtools/json-schema-ref-parser@9.1.2':
+ dependencies:
+ '@jsdevtools/ono': 7.1.3
+ '@types/json-schema': 7.0.15
+ call-me-maybe: 1.0.2
+ js-yaml: 4.1.0
+
+ '@apidevtools/openapi-schemas@2.1.0': {}
+
+ '@apidevtools/swagger-methods@3.0.2': {}
+
+ '@apidevtools/swagger-parser@10.0.3(openapi-types@12.1.3)':
+ dependencies:
+ '@apidevtools/json-schema-ref-parser': 9.1.2
+ '@apidevtools/openapi-schemas': 2.1.0
+ '@apidevtools/swagger-methods': 3.0.2
+ '@jsdevtools/ono': 7.1.3
+ call-me-maybe: 1.0.2
+ openapi-types: 12.1.3
+ z-schema: 5.0.5
+
+ '@colors/colors@1.6.0': {}
+
+ '@dabh/diagnostics@2.0.3':
+ dependencies:
+ colorspace: 1.1.4
+ enabled: 2.0.0
+ kuler: 2.0.0
+
'@esbuild/aix-ppc64@0.25.2':
optional: true
@@ -1675,41 +2557,40 @@ snapshots:
'@esbuild/win32-x64@0.25.2':
optional: true
- '@eslint-community/eslint-utils@4.5.1(eslint@9.28.0(jiti@2.4.2))':
- dependencies:
- eslint: 9.28.0(jiti@2.4.2)
- eslint-visitor-keys: 3.4.3
-
- '@eslint-community/eslint-utils@4.7.0(eslint@9.28.0(jiti@2.4.2))':
+ '@eslint-community/eslint-utils@4.7.0(eslint@9.31.0(jiti@2.4.2))':
dependencies:
- eslint: 9.28.0(jiti@2.4.2)
+ eslint: 9.31.0(jiti@2.4.2)
eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.12.1': {}
- '@eslint/compat@1.2.9(eslint@9.28.0(jiti@2.4.2))':
+ '@eslint/compat@1.3.1(eslint@9.31.0(jiti@2.4.2))':
optionalDependencies:
- eslint: 9.28.0(jiti@2.4.2)
+ eslint: 9.31.0(jiti@2.4.2)
- '@eslint/config-array@0.20.0':
+ '@eslint/config-array@0.21.0':
dependencies:
'@eslint/object-schema': 2.1.6
- debug: 4.4.0
+ debug: 4.4.1(supports-color@5.5.0)
minimatch: 3.1.2
transitivePeerDependencies:
- supports-color
- '@eslint/config-helpers@0.2.1': {}
+ '@eslint/config-helpers@0.3.0': {}
'@eslint/core@0.14.0':
dependencies:
'@types/json-schema': 7.0.15
+ '@eslint/core@0.15.1':
+ dependencies:
+ '@types/json-schema': 7.0.15
+
'@eslint/eslintrc@3.3.1':
dependencies:
ajv: 6.12.6
- debug: 4.4.0
- espree: 10.3.0
+ debug: 4.4.1(supports-color@5.5.0)
+ espree: 10.4.0
globals: 14.0.0
ignore: 5.3.2
import-fresh: 3.3.1
@@ -1719,7 +2600,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@eslint/js@9.28.0': {}
+ '@eslint/js@9.31.0': {}
'@eslint/object-schema@2.1.6': {}
@@ -1762,51 +2643,50 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0
- '@lucide/svelte@0.513.0(svelte@5.33.18)':
+ '@jsdevtools/ono@7.1.3': {}
+
+ '@lucide/svelte@0.525.0(svelte@5.36.14)':
dependencies:
- svelte: 5.33.18
+ svelte: 5.36.14
'@polka/url@1.0.0-next.29': {}
- '@prisma/client@6.5.0(prisma@6.5.0(typescript@5.8.3))(typescript@5.8.3)':
+ '@prisma/client@6.12.0(prisma@6.12.0(typescript@5.8.3))(typescript@5.8.3)':
optionalDependencies:
- prisma: 6.5.0(typescript@5.8.3)
+ prisma: 6.12.0(typescript@5.8.3)
typescript: 5.8.3
- '@prisma/config@6.5.0':
+ '@prisma/config@6.12.0':
dependencies:
- esbuild: 0.25.2
- esbuild-register: 3.6.0(esbuild@0.25.2)
- transitivePeerDependencies:
- - supports-color
+ jiti: 2.4.2
- '@prisma/debug@6.5.0': {}
+ '@prisma/debug@6.12.0': {}
- '@prisma/engines-version@6.5.0-73.173f8d54f8d52e692c7e27e72a88314ec7aeff60': {}
+ '@prisma/engines-version@6.12.0-15.8047c96bbd92db98a2abc7c9323ce77c02c89dbc': {}
- '@prisma/engines@6.5.0':
+ '@prisma/engines@6.12.0':
dependencies:
- '@prisma/debug': 6.5.0
- '@prisma/engines-version': 6.5.0-73.173f8d54f8d52e692c7e27e72a88314ec7aeff60
- '@prisma/fetch-engine': 6.5.0
- '@prisma/get-platform': 6.5.0
+ '@prisma/debug': 6.12.0
+ '@prisma/engines-version': 6.12.0-15.8047c96bbd92db98a2abc7c9323ce77c02c89dbc
+ '@prisma/fetch-engine': 6.12.0
+ '@prisma/get-platform': 6.12.0
- '@prisma/fetch-engine@6.5.0':
+ '@prisma/fetch-engine@6.12.0':
dependencies:
- '@prisma/debug': 6.5.0
- '@prisma/engines-version': 6.5.0-73.173f8d54f8d52e692c7e27e72a88314ec7aeff60
- '@prisma/get-platform': 6.5.0
+ '@prisma/debug': 6.12.0
+ '@prisma/engines-version': 6.12.0-15.8047c96bbd92db98a2abc7c9323ce77c02c89dbc
+ '@prisma/get-platform': 6.12.0
- '@prisma/get-platform@6.5.0':
+ '@prisma/get-platform@6.12.0':
dependencies:
- '@prisma/debug': 6.5.0
+ '@prisma/debug': 6.12.0
'@rollup/plugin-commonjs@28.0.3(rollup@4.39.0)':
dependencies:
'@rollup/pluginutils': 5.1.4(rollup@4.39.0)
commondir: 1.0.1
estree-walker: 2.0.2
- fdir: 6.4.3(picomatch@4.0.2)
+ fdir: 6.4.6(picomatch@4.0.2)
is-reference: 1.2.1
magic-string: 0.30.17
picomatch: 4.0.2
@@ -1840,79 +2720,141 @@ snapshots:
'@rollup/rollup-android-arm-eabi@4.39.0':
optional: true
+ '@rollup/rollup-android-arm-eabi@4.45.1':
+ optional: true
+
'@rollup/rollup-android-arm64@4.39.0':
optional: true
+ '@rollup/rollup-android-arm64@4.45.1':
+ optional: true
+
'@rollup/rollup-darwin-arm64@4.39.0':
optional: true
+ '@rollup/rollup-darwin-arm64@4.45.1':
+ optional: true
+
'@rollup/rollup-darwin-x64@4.39.0':
optional: true
+ '@rollup/rollup-darwin-x64@4.45.1':
+ optional: true
+
'@rollup/rollup-freebsd-arm64@4.39.0':
optional: true
+ '@rollup/rollup-freebsd-arm64@4.45.1':
+ optional: true
+
'@rollup/rollup-freebsd-x64@4.39.0':
optional: true
+ '@rollup/rollup-freebsd-x64@4.45.1':
+ optional: true
+
'@rollup/rollup-linux-arm-gnueabihf@4.39.0':
optional: true
+ '@rollup/rollup-linux-arm-gnueabihf@4.45.1':
+ optional: true
+
'@rollup/rollup-linux-arm-musleabihf@4.39.0':
optional: true
+ '@rollup/rollup-linux-arm-musleabihf@4.45.1':
+ optional: true
+
'@rollup/rollup-linux-arm64-gnu@4.39.0':
optional: true
+ '@rollup/rollup-linux-arm64-gnu@4.45.1':
+ optional: true
+
'@rollup/rollup-linux-arm64-musl@4.39.0':
optional: true
+ '@rollup/rollup-linux-arm64-musl@4.45.1':
+ optional: true
+
'@rollup/rollup-linux-loongarch64-gnu@4.39.0':
optional: true
+ '@rollup/rollup-linux-loongarch64-gnu@4.45.1':
+ optional: true
+
'@rollup/rollup-linux-powerpc64le-gnu@4.39.0':
optional: true
+ '@rollup/rollup-linux-powerpc64le-gnu@4.45.1':
+ optional: true
+
'@rollup/rollup-linux-riscv64-gnu@4.39.0':
optional: true
+ '@rollup/rollup-linux-riscv64-gnu@4.45.1':
+ optional: true
+
'@rollup/rollup-linux-riscv64-musl@4.39.0':
optional: true
+ '@rollup/rollup-linux-riscv64-musl@4.45.1':
+ optional: true
+
'@rollup/rollup-linux-s390x-gnu@4.39.0':
optional: true
+ '@rollup/rollup-linux-s390x-gnu@4.45.1':
+ optional: true
+
'@rollup/rollup-linux-x64-gnu@4.39.0':
optional: true
+ '@rollup/rollup-linux-x64-gnu@4.45.1':
+ optional: true
+
'@rollup/rollup-linux-x64-musl@4.39.0':
optional: true
+ '@rollup/rollup-linux-x64-musl@4.45.1':
+ optional: true
+
'@rollup/rollup-win32-arm64-msvc@4.39.0':
optional: true
+ '@rollup/rollup-win32-arm64-msvc@4.45.1':
+ optional: true
+
'@rollup/rollup-win32-ia32-msvc@4.39.0':
optional: true
+ '@rollup/rollup-win32-ia32-msvc@4.45.1':
+ optional: true
+
'@rollup/rollup-win32-x64-msvc@4.39.0':
optional: true
+ '@rollup/rollup-win32-x64-msvc@4.45.1':
+ optional: true
+
+ '@scarf/scarf@1.4.0': {}
+
'@sveltejs/acorn-typescript@1.0.5(acorn@8.14.1)':
dependencies:
acorn: 8.14.1
- '@sveltejs/adapter-node@5.2.12(@sveltejs/kit@2.21.4(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))':
+ '@sveltejs/adapter-node@5.2.13(@sveltejs/kit@2.25.2(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1)))':
dependencies:
'@rollup/plugin-commonjs': 28.0.3(rollup@4.39.0)
'@rollup/plugin-json': 6.1.0(rollup@4.39.0)
'@rollup/plugin-node-resolve': 16.0.1(rollup@4.39.0)
- '@sveltejs/kit': 2.21.4(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
+ '@sveltejs/kit': 2.25.2(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1))
rollup: 4.39.0
- '@sveltejs/kit@2.21.4(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))':
+ '@sveltejs/kit@2.25.2(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1))':
dependencies:
'@sveltejs/acorn-typescript': 1.0.5(acorn@8.14.1)
- '@sveltejs/vite-plugin-svelte': 5.1.0(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
+ '@sveltejs/vite-plugin-svelte': 6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1))
'@types/cookie': 0.6.0
acorn: 8.14.1
cookie: 0.6.0
@@ -1924,33 +2866,32 @@ snapshots:
sade: 1.8.1
set-cookie-parser: 2.7.1
sirv: 3.0.1
- svelte: 5.33.18
- vite: 6.3.5(jiti@2.4.2)(lightningcss@1.30.1)
- vitefu: 1.0.6(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
+ svelte: 5.36.14
+ vite: 7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1)
- '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))':
+ '@sveltejs/vite-plugin-svelte-inspector@5.0.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1))':
dependencies:
- '@sveltejs/vite-plugin-svelte': 5.1.0(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
- debug: 4.4.1
- svelte: 5.33.18
- vite: 6.3.5(jiti@2.4.2)(lightningcss@1.30.1)
+ '@sveltejs/vite-plugin-svelte': 6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1))
+ debug: 4.4.1(supports-color@5.5.0)
+ svelte: 5.36.14
+ vite: 7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1)
transitivePeerDependencies:
- supports-color
- '@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))':
+ '@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1))':
dependencies:
- '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.33.18)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
- debug: 4.4.1
+ '@sveltejs/vite-plugin-svelte-inspector': 5.0.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.36.14)(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1))
+ debug: 4.4.1(supports-color@5.5.0)
deepmerge: 4.3.1
kleur: 4.1.5
magic-string: 0.30.17
- svelte: 5.33.18
- vite: 6.3.5(jiti@2.4.2)(lightningcss@1.30.1)
- vitefu: 1.0.6(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))
+ svelte: 5.36.14
+ vite: 7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1)
+ vitefu: 1.1.1(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1))
transitivePeerDependencies:
- supports-color
- '@tailwindcss/node@4.1.8':
+ '@tailwindcss/node@4.1.11':
dependencies:
'@ampproject/remapping': 2.3.0
enhanced-resolve: 5.18.1
@@ -1958,91 +2899,179 @@ snapshots:
lightningcss: 1.30.1
magic-string: 0.30.17
source-map-js: 1.2.1
- tailwindcss: 4.1.8
+ tailwindcss: 4.1.11
- '@tailwindcss/oxide-android-arm64@4.1.8':
+ '@tailwindcss/oxide-android-arm64@4.1.11':
optional: true
- '@tailwindcss/oxide-darwin-arm64@4.1.8':
+ '@tailwindcss/oxide-darwin-arm64@4.1.11':
optional: true
- '@tailwindcss/oxide-darwin-x64@4.1.8':
+ '@tailwindcss/oxide-darwin-x64@4.1.11':
optional: true
- '@tailwindcss/oxide-freebsd-x64@4.1.8':
+ '@tailwindcss/oxide-freebsd-x64@4.1.11':
optional: true
- '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.8':
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11':
optional: true
- '@tailwindcss/oxide-linux-arm64-gnu@4.1.8':
+ '@tailwindcss/oxide-linux-arm64-gnu@4.1.11':
optional: true
- '@tailwindcss/oxide-linux-arm64-musl@4.1.8':
+ '@tailwindcss/oxide-linux-arm64-musl@4.1.11':
optional: true
- '@tailwindcss/oxide-linux-x64-gnu@4.1.8':
+ '@tailwindcss/oxide-linux-x64-gnu@4.1.11':
optional: true
- '@tailwindcss/oxide-linux-x64-musl@4.1.8':
+ '@tailwindcss/oxide-linux-x64-musl@4.1.11':
optional: true
- '@tailwindcss/oxide-wasm32-wasi@4.1.8':
+ '@tailwindcss/oxide-wasm32-wasi@4.1.11':
optional: true
- '@tailwindcss/oxide-win32-arm64-msvc@4.1.8':
+ '@tailwindcss/oxide-win32-arm64-msvc@4.1.11':
optional: true
- '@tailwindcss/oxide-win32-x64-msvc@4.1.8':
+ '@tailwindcss/oxide-win32-x64-msvc@4.1.11':
optional: true
- '@tailwindcss/oxide@4.1.8':
+ '@tailwindcss/oxide@4.1.11':
dependencies:
detect-libc: 2.0.4
tar: 7.4.3
optionalDependencies:
- '@tailwindcss/oxide-android-arm64': 4.1.8
- '@tailwindcss/oxide-darwin-arm64': 4.1.8
- '@tailwindcss/oxide-darwin-x64': 4.1.8
- '@tailwindcss/oxide-freebsd-x64': 4.1.8
- '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.8
- '@tailwindcss/oxide-linux-arm64-gnu': 4.1.8
- '@tailwindcss/oxide-linux-arm64-musl': 4.1.8
- '@tailwindcss/oxide-linux-x64-gnu': 4.1.8
- '@tailwindcss/oxide-linux-x64-musl': 4.1.8
- '@tailwindcss/oxide-wasm32-wasi': 4.1.8
- '@tailwindcss/oxide-win32-arm64-msvc': 4.1.8
- '@tailwindcss/oxide-win32-x64-msvc': 4.1.8
-
- '@tailwindcss/typography@0.5.16(tailwindcss@4.1.8)':
+ '@tailwindcss/oxide-android-arm64': 4.1.11
+ '@tailwindcss/oxide-darwin-arm64': 4.1.11
+ '@tailwindcss/oxide-darwin-x64': 4.1.11
+ '@tailwindcss/oxide-freebsd-x64': 4.1.11
+ '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.11
+ '@tailwindcss/oxide-linux-arm64-gnu': 4.1.11
+ '@tailwindcss/oxide-linux-arm64-musl': 4.1.11
+ '@tailwindcss/oxide-linux-x64-gnu': 4.1.11
+ '@tailwindcss/oxide-linux-x64-musl': 4.1.11
+ '@tailwindcss/oxide-wasm32-wasi': 4.1.11
+ '@tailwindcss/oxide-win32-arm64-msvc': 4.1.11
+ '@tailwindcss/oxide-win32-x64-msvc': 4.1.11
+
+ '@tailwindcss/typography@0.5.16(tailwindcss@4.1.11)':
dependencies:
lodash.castarray: 4.4.0
lodash.isplainobject: 4.0.6
lodash.merge: 4.6.2
postcss-selector-parser: 6.0.10
- tailwindcss: 4.1.8
+ tailwindcss: 4.1.11
+
+ '@tailwindcss/vite@4.1.11(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1))':
+ dependencies:
+ '@tailwindcss/node': 4.1.11
+ '@tailwindcss/oxide': 4.1.11
+ tailwindcss: 4.1.11
+ vite: 7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1)
+
+ '@types/bcryptjs@3.0.0':
+ dependencies:
+ bcryptjs: 3.0.2
+
+ '@types/body-parser@1.19.6':
+ dependencies:
+ '@types/connect': 3.4.38
+ '@types/node': 24.1.0
- '@tailwindcss/vite@4.1.8(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))':
+ '@types/connect@3.4.38':
dependencies:
- '@tailwindcss/node': 4.1.8
- '@tailwindcss/oxide': 4.1.8
- tailwindcss: 4.1.8
- vite: 6.3.5(jiti@2.4.2)(lightningcss@1.30.1)
+ '@types/node': 24.1.0
'@types/cookie@0.6.0': {}
+ '@types/cors@2.8.19':
+ dependencies:
+ '@types/node': 24.1.0
+
'@types/estree@1.0.7': {}
+ '@types/estree@1.0.8': {}
+
+ '@types/express-serve-static-core@5.0.7':
+ dependencies:
+ '@types/node': 24.1.0
+ '@types/qs': 6.14.0
+ '@types/range-parser': 1.2.7
+ '@types/send': 0.17.5
+
+ '@types/express@5.0.3':
+ dependencies:
+ '@types/body-parser': 1.19.6
+ '@types/express-serve-static-core': 5.0.7
+ '@types/serve-static': 1.15.8
+
+ '@types/http-errors@2.0.5': {}
+
'@types/json-schema@7.0.15': {}
+ '@types/jsonwebtoken@9.0.10':
+ dependencies:
+ '@types/ms': 2.1.0
+ '@types/node': 24.1.0
+
+ '@types/mime@1.3.5': {}
+
+ '@types/morgan@1.9.10':
+ dependencies:
+ '@types/node': 24.1.0
+
+ '@types/ms@2.1.0': {}
+
+ '@types/node@24.1.0':
+ dependencies:
+ undici-types: 7.8.0
+
+ '@types/qs@6.14.0': {}
+
+ '@types/range-parser@1.2.7': {}
+
'@types/resolve@1.20.2': {}
+ '@types/send@0.17.5':
+ dependencies:
+ '@types/mime': 1.3.5
+ '@types/node': 24.1.0
+
+ '@types/serve-static@1.15.8':
+ dependencies:
+ '@types/http-errors': 2.0.5
+ '@types/node': 24.1.0
+ '@types/send': 0.17.5
+
+ '@types/swagger-jsdoc@6.0.4': {}
+
+ '@types/swagger-ui-express@4.1.8':
+ dependencies:
+ '@types/express': 5.0.3
+ '@types/serve-static': 1.15.8
+
+ '@types/triple-beam@1.3.5': {}
+
+ accepts@2.0.0:
+ dependencies:
+ mime-types: 3.0.1
+ negotiator: 1.0.0
+
acorn-jsx@5.3.2(acorn@8.14.1):
dependencies:
acorn: 8.14.1
+ acorn-jsx@5.3.2(acorn@8.15.0):
+ dependencies:
+ acorn: 8.15.0
+
acorn@8.14.1: {}
+ acorn@8.15.0: {}
+
+ agent-base@7.1.4: {}
+
ajv@6.12.6:
dependencies:
fast-deep-equal: 3.1.3
@@ -2054,16 +3083,23 @@ snapshots:
dependencies:
color-convert: 2.0.1
+ anymatch@3.1.3:
+ dependencies:
+ normalize-path: 3.0.0
+ picomatch: 2.3.1
+
argparse@2.0.1: {}
aria-query@5.3.2: {}
+ async@3.2.6: {}
+
asynckit@0.4.0: {}
- axios@1.9.0:
+ axios@1.11.0:
dependencies:
follow-redirects: 1.15.9
- form-data: 4.0.2
+ form-data: 4.0.4
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
@@ -2072,16 +3108,57 @@ snapshots:
balanced-match@1.0.2: {}
+ base64-js@1.5.1: {}
+
+ basic-auth@2.0.1:
+ dependencies:
+ safe-buffer: 5.1.2
+
+ bcryptjs@3.0.2: {}
+
+ bignumber.js@9.3.1: {}
+
+ binary-extensions@2.3.0: {}
+
+ body-parser@2.2.0:
+ dependencies:
+ bytes: 3.1.2
+ content-type: 1.0.5
+ debug: 4.4.1(supports-color@5.5.0)
+ http-errors: 2.0.0
+ iconv-lite: 0.6.3
+ on-finished: 2.4.1
+ qs: 6.14.0
+ raw-body: 3.0.0
+ type-is: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+
brace-expansion@1.1.11:
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
+ buffer-equal-constant-time@1.0.1: {}
+
+ bytes@3.1.2: {}
+
call-bind-apply-helpers@1.0.2:
dependencies:
es-errors: 1.3.0
function-bind: 1.1.2
+ call-bound@1.0.4:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ get-intrinsic: 1.3.0
+
+ call-me-maybe@1.0.2: {}
+
callsites@3.1.0: {}
chalk@4.1.2:
@@ -2089,6 +3166,18 @@ snapshots:
ansi-styles: 4.3.0
supports-color: 7.2.0
+ chokidar@3.6.0:
+ dependencies:
+ anymatch: 3.1.3
+ braces: 3.0.3
+ glob-parent: 5.1.2
+ is-binary-path: 2.1.0
+ is-glob: 4.0.3
+ normalize-path: 3.0.0
+ readdirp: 3.6.0
+ optionalDependencies:
+ fsevents: 2.3.3
+
chokidar@4.0.3:
dependencies:
readdirp: 4.1.2
@@ -2097,21 +3186,62 @@ snapshots:
clsx@2.1.1: {}
+ color-convert@1.9.3:
+ dependencies:
+ color-name: 1.1.3
+
color-convert@2.0.1:
dependencies:
color-name: 1.1.4
+ color-name@1.1.3: {}
+
color-name@1.1.4: {}
+ color-string@1.9.1:
+ dependencies:
+ color-name: 1.1.4
+ simple-swizzle: 0.2.2
+
+ color@3.2.1:
+ dependencies:
+ color-convert: 1.9.3
+ color-string: 1.9.1
+
+ colorspace@1.1.4:
+ dependencies:
+ color: 3.2.1
+ text-hex: 1.0.0
+
combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
+ commander@6.2.0: {}
+
+ commander@9.5.0:
+ optional: true
+
commondir@1.0.1: {}
concat-map@0.0.1: {}
- cookie@0.6.0: {}
+ content-disposition@1.0.0:
+ dependencies:
+ safe-buffer: 5.2.1
+
+ content-type@1.0.5: {}
+
+ cookie-signature@1.2.2: {}
+
+ cookie@0.6.0: {}
+
+ cookie@0.7.2: {}
+
+ cors@2.8.5:
+ dependencies:
+ object-assign: 4.1.1
+ vary: 1.1.2
cross-spawn@7.0.6:
dependencies:
@@ -2121,15 +3251,19 @@ snapshots:
cssesc@3.0.0: {}
+ data-uri-to-buffer@4.0.1: {}
+
date-fns@4.1.0: {}
- debug@4.4.0:
+ debug@2.6.9:
dependencies:
- ms: 2.1.3
+ ms: 2.0.0
- debug@4.4.1:
+ debug@4.4.1(supports-color@5.5.0):
dependencies:
ms: 2.1.3
+ optionalDependencies:
+ supports-color: 5.5.0
deep-is@0.1.4: {}
@@ -2137,18 +3271,34 @@ snapshots:
delayed-stream@1.0.0: {}
- detect-libc@2.0.3: {}
+ depd@2.0.0: {}
detect-libc@2.0.4: {}
devalue@5.1.1: {}
+ doctrine@3.0.0:
+ dependencies:
+ esutils: 2.0.3
+
+ dotenv@17.2.1: {}
+
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
es-errors: 1.3.0
gopd: 1.2.0
+ ecdsa-sig-formatter@1.0.11:
+ dependencies:
+ safe-buffer: 5.2.1
+
+ ee-first@1.1.1: {}
+
+ enabled@2.0.0: {}
+
+ encodeurl@2.0.0: {}
+
enhanced-resolve@5.18.1:
dependencies:
graceful-fs: 4.2.11
@@ -2169,13 +3319,6 @@ snapshots:
has-tostringtag: 1.0.2
hasown: 2.0.2
- esbuild-register@3.6.0(esbuild@0.25.2):
- dependencies:
- debug: 4.4.0
- esbuild: 0.25.2
- transitivePeerDependencies:
- - supports-color
-
esbuild@0.25.2:
optionalDependencies:
'@esbuild/aix-ppc64': 0.25.2
@@ -2204,27 +3347,29 @@ snapshots:
'@esbuild/win32-ia32': 0.25.2
'@esbuild/win32-x64': 0.25.2
+ escape-html@1.0.3: {}
+
escape-string-regexp@4.0.0: {}
- eslint-config-prettier@10.1.5(eslint@9.28.0(jiti@2.4.2)):
+ eslint-config-prettier@10.1.8(eslint@9.31.0(jiti@2.4.2)):
dependencies:
- eslint: 9.28.0(jiti@2.4.2)
+ eslint: 9.31.0(jiti@2.4.2)
- eslint-plugin-svelte@3.9.2(eslint@9.28.0(jiti@2.4.2))(svelte@5.33.18):
+ eslint-plugin-svelte@3.11.0(eslint@9.31.0(jiti@2.4.2))(svelte@5.36.14):
dependencies:
- '@eslint-community/eslint-utils': 4.7.0(eslint@9.28.0(jiti@2.4.2))
+ '@eslint-community/eslint-utils': 4.7.0(eslint@9.31.0(jiti@2.4.2))
'@jridgewell/sourcemap-codec': 1.5.0
- eslint: 9.28.0(jiti@2.4.2)
+ eslint: 9.31.0(jiti@2.4.2)
esutils: 2.0.3
- globals: 16.2.0
- known-css-properties: 0.36.0
+ globals: 16.3.0
+ known-css-properties: 0.37.0
postcss: 8.5.3
postcss-load-config: 3.1.4(postcss@8.5.3)
postcss-safe-parser: 7.0.1(postcss@8.5.3)
semver: 7.7.1
- svelte-eslint-parser: 1.2.0(svelte@5.33.18)
+ svelte-eslint-parser: 1.3.0(svelte@5.36.14)
optionalDependencies:
- svelte: 5.33.18
+ svelte: 5.36.14
transitivePeerDependencies:
- ts-node
@@ -2233,19 +3378,26 @@ snapshots:
esrecurse: 4.3.0
estraverse: 5.3.0
+ eslint-scope@8.4.0:
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+
eslint-visitor-keys@3.4.3: {}
eslint-visitor-keys@4.2.0: {}
- eslint@9.28.0(jiti@2.4.2):
+ eslint-visitor-keys@4.2.1: {}
+
+ eslint@9.31.0(jiti@2.4.2):
dependencies:
- '@eslint-community/eslint-utils': 4.5.1(eslint@9.28.0(jiti@2.4.2))
+ '@eslint-community/eslint-utils': 4.7.0(eslint@9.31.0(jiti@2.4.2))
'@eslint-community/regexpp': 4.12.1
- '@eslint/config-array': 0.20.0
- '@eslint/config-helpers': 0.2.1
- '@eslint/core': 0.14.0
+ '@eslint/config-array': 0.21.0
+ '@eslint/config-helpers': 0.3.0
+ '@eslint/core': 0.15.1
'@eslint/eslintrc': 3.3.1
- '@eslint/js': 9.28.0
+ '@eslint/js': 9.31.0
'@eslint/plugin-kit': 0.3.1
'@humanfs/node': 0.16.6
'@humanwhocodes/module-importer': 1.0.1
@@ -2255,11 +3407,11 @@ snapshots:
ajv: 6.12.6
chalk: 4.1.2
cross-spawn: 7.0.6
- debug: 4.4.0
+ debug: 4.4.1(supports-color@5.5.0)
escape-string-regexp: 4.0.0
- eslint-scope: 8.3.0
- eslint-visitor-keys: 4.2.0
- espree: 10.3.0
+ eslint-scope: 8.4.0
+ eslint-visitor-keys: 4.2.1
+ espree: 10.4.0
esquery: 1.6.0
esutils: 2.0.3
fast-deep-equal: 3.1.3
@@ -2287,11 +3439,17 @@ snapshots:
acorn-jsx: 5.3.2(acorn@8.14.1)
eslint-visitor-keys: 4.2.0
+ espree@10.4.0:
+ dependencies:
+ acorn: 8.15.0
+ acorn-jsx: 5.3.2(acorn@8.15.0)
+ eslint-visitor-keys: 4.2.1
+
esquery@1.6.0:
dependencies:
estraverse: 5.3.0
- esrap@1.4.9:
+ esrap@2.1.0:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
@@ -2305,24 +3463,83 @@ snapshots:
esutils@2.0.3: {}
+ etag@1.8.1: {}
+
+ express-rate-limit@8.0.1(express@5.1.0):
+ dependencies:
+ express: 5.1.0
+ ip-address: 10.0.1
+
+ express@5.1.0:
+ dependencies:
+ accepts: 2.0.0
+ body-parser: 2.2.0
+ content-disposition: 1.0.0
+ content-type: 1.0.5
+ cookie: 0.7.2
+ cookie-signature: 1.2.2
+ debug: 4.4.1(supports-color@5.5.0)
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ etag: 1.8.1
+ finalhandler: 2.1.0
+ fresh: 2.0.0
+ http-errors: 2.0.0
+ merge-descriptors: 2.0.0
+ mime-types: 3.0.1
+ on-finished: 2.4.1
+ once: 1.4.0
+ parseurl: 1.3.3
+ proxy-addr: 2.0.7
+ qs: 6.14.0
+ range-parser: 1.2.1
+ router: 2.2.0
+ send: 1.2.0
+ serve-static: 2.2.0
+ statuses: 2.0.2
+ type-is: 2.0.1
+ vary: 1.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ extend@3.0.2: {}
+
fast-deep-equal@3.1.3: {}
fast-json-stable-stringify@2.1.0: {}
fast-levenshtein@2.0.6: {}
- fdir@6.4.3(picomatch@4.0.2):
- optionalDependencies:
- picomatch: 4.0.2
-
fdir@6.4.6(picomatch@4.0.2):
optionalDependencies:
picomatch: 4.0.2
+ fecha@4.2.3: {}
+
+ fetch-blob@3.2.0:
+ dependencies:
+ node-domexception: 1.0.0
+ web-streams-polyfill: 3.3.3
+
file-entry-cache@8.0.0:
dependencies:
flat-cache: 4.0.1
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
+ finalhandler@2.1.0:
+ dependencies:
+ debug: 4.4.1(supports-color@5.5.0)
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ on-finished: 2.4.1
+ parseurl: 1.3.3
+ statuses: 2.0.2
+ transitivePeerDependencies:
+ - supports-color
+
find-up@5.0.0:
dependencies:
locate-path: 6.0.0
@@ -2335,20 +3552,49 @@ snapshots:
flatted@3.3.3: {}
+ fn.name@1.1.0: {}
+
follow-redirects@1.15.9: {}
- form-data@4.0.2:
+ form-data@4.0.4:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
es-set-tostringtag: 2.1.0
+ hasown: 2.0.2
mime-types: 2.1.35
+ formdata-polyfill@4.0.10:
+ dependencies:
+ fetch-blob: 3.2.0
+
+ forwarded@0.2.0: {}
+
+ fresh@2.0.0: {}
+
+ fs.realpath@1.0.0: {}
+
fsevents@2.3.3:
optional: true
function-bind@1.1.2: {}
+ gaxios@7.1.1:
+ dependencies:
+ extend: 3.0.2
+ https-proxy-agent: 7.0.6
+ node-fetch: 3.3.2
+ transitivePeerDependencies:
+ - supports-color
+
+ gcp-metadata@7.0.1:
+ dependencies:
+ gaxios: 7.1.1
+ google-logging-utils: 1.1.1
+ json-bigint: 1.0.0
+ transitivePeerDependencies:
+ - supports-color
+
get-intrinsic@1.3.0:
dependencies:
call-bind-apply-helpers: 1.0.2
@@ -2367,18 +3613,54 @@ snapshots:
dunder-proto: 1.0.1
es-object-atoms: 1.1.1
+ glob-parent@5.1.2:
+ dependencies:
+ is-glob: 4.0.3
+
glob-parent@6.0.2:
dependencies:
is-glob: 4.0.3
+ glob@7.1.6:
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 3.1.2
+ once: 1.4.0
+ path-is-absolute: 1.0.1
+
globals@14.0.0: {}
- globals@16.2.0: {}
+ globals@16.3.0: {}
+
+ google-auth-library@10.2.0:
+ dependencies:
+ base64-js: 1.5.1
+ ecdsa-sig-formatter: 1.0.11
+ gaxios: 7.1.1
+ gcp-metadata: 7.0.1
+ google-logging-utils: 1.1.1
+ gtoken: 8.0.0
+ jws: 4.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ google-logging-utils@1.1.1: {}
gopd@1.2.0: {}
graceful-fs@4.2.11: {}
+ gtoken@8.0.0:
+ dependencies:
+ gaxios: 7.1.1
+ jws: 4.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ has-flag@3.0.0: {}
+
has-flag@4.0.0: {}
has-symbols@1.1.0: {}
@@ -2391,8 +3673,31 @@ snapshots:
dependencies:
function-bind: 1.1.2
+ helmet@8.1.0: {}
+
highlight.js@11.11.1: {}
+ http-errors@2.0.0:
+ dependencies:
+ depd: 2.0.0
+ inherits: 2.0.4
+ setprototypeof: 1.2.0
+ statuses: 2.0.1
+ toidentifier: 1.0.1
+
+ https-proxy-agent@7.0.6:
+ dependencies:
+ agent-base: 7.1.4
+ debug: 4.4.1(supports-color@5.5.0)
+ transitivePeerDependencies:
+ - supports-color
+
+ iconv-lite@0.6.3:
+ dependencies:
+ safer-buffer: 2.1.2
+
+ ignore-by-default@1.0.1: {}
+
ignore@5.3.2: {}
import-fresh@3.3.1:
@@ -2402,6 +3707,23 @@ snapshots:
imurmurhash@0.1.4: {}
+ inflight@1.0.6:
+ dependencies:
+ once: 1.4.0
+ wrappy: 1.0.2
+
+ inherits@2.0.4: {}
+
+ ip-address@10.0.1: {}
+
+ ipaddr.js@1.9.1: {}
+
+ is-arrayish@0.3.2: {}
+
+ is-binary-path@2.1.0:
+ dependencies:
+ binary-extensions: 2.3.0
+
is-core-module@2.16.1:
dependencies:
hasown: 2.0.2
@@ -2414,6 +3736,10 @@ snapshots:
is-module@1.0.0: {}
+ is-number@7.0.0: {}
+
+ is-promise@4.0.0: {}
+
is-reference@1.2.1:
dependencies:
'@types/estree': 1.0.7
@@ -2422,6 +3748,8 @@ snapshots:
dependencies:
'@types/estree': 1.0.7
+ is-stream@2.0.1: {}
+
isexe@2.0.0: {}
jiti@2.4.2: {}
@@ -2430,26 +3758,67 @@ snapshots:
dependencies:
argparse: 2.0.1
+ json-bigint@1.0.0:
+ dependencies:
+ bignumber.js: 9.3.1
+
json-buffer@3.0.1: {}
json-schema-traverse@0.4.1: {}
json-stable-stringify-without-jsonify@1.0.1: {}
+ jsonwebtoken@9.0.2:
+ dependencies:
+ jws: 3.2.2
+ lodash.includes: 4.3.0
+ lodash.isboolean: 3.0.3
+ lodash.isinteger: 4.0.4
+ lodash.isnumber: 3.0.3
+ lodash.isplainobject: 4.0.6
+ lodash.isstring: 4.0.1
+ lodash.once: 4.1.1
+ ms: 2.1.3
+ semver: 7.7.1
+
+ jwa@1.4.2:
+ dependencies:
+ buffer-equal-constant-time: 1.0.1
+ ecdsa-sig-formatter: 1.0.11
+ safe-buffer: 5.2.1
+
+ jwa@2.0.1:
+ dependencies:
+ buffer-equal-constant-time: 1.0.1
+ ecdsa-sig-formatter: 1.0.11
+ safe-buffer: 5.2.1
+
+ jws@3.2.2:
+ dependencies:
+ jwa: 1.4.2
+ safe-buffer: 5.2.1
+
+ jws@4.0.0:
+ dependencies:
+ jwa: 2.0.1
+ safe-buffer: 5.2.1
+
keyv@4.5.4:
dependencies:
json-buffer: 3.0.1
kleur@4.1.5: {}
- known-css-properties@0.36.0: {}
+ known-css-properties@0.37.0: {}
+
+ kuler@2.0.0: {}
levn@0.4.1:
dependencies:
prelude-ls: 1.2.1
type-check: 0.4.0
- libphonenumber-js@1.12.9: {}
+ libphonenumber-js@1.12.10: {}
lightningcss-darwin-arm64@1.30.1:
optional: true
@@ -2483,7 +3852,7 @@ snapshots:
lightningcss@1.30.1:
dependencies:
- detect-libc: 2.0.3
+ detect-libc: 2.0.4
optionalDependencies:
lightningcss-darwin-arm64: 1.30.1
lightningcss-darwin-x64: 1.30.1
@@ -2506,24 +3875,61 @@ snapshots:
lodash.castarray@4.4.0: {}
+ lodash.get@4.4.2: {}
+
+ lodash.includes@4.3.0: {}
+
+ lodash.isboolean@3.0.3: {}
+
+ lodash.isequal@4.5.0: {}
+
+ lodash.isinteger@4.0.4: {}
+
+ lodash.isnumber@3.0.3: {}
+
lodash.isplainobject@4.0.6: {}
+ lodash.isstring@4.0.1: {}
+
lodash.merge@4.6.2: {}
+ lodash.mergewith@4.6.2: {}
+
+ lodash.once@4.1.1: {}
+
+ logform@2.7.0:
+ dependencies:
+ '@colors/colors': 1.6.0
+ '@types/triple-beam': 1.3.5
+ fecha: 4.2.3
+ ms: 2.1.3
+ safe-stable-stringify: 2.5.0
+ triple-beam: 1.4.1
+
magic-string@0.30.17:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
- marked@15.0.12: {}
+ marked@16.1.1: {}
math-intrinsics@1.1.0: {}
+ media-typer@1.1.0: {}
+
+ merge-descriptors@2.0.0: {}
+
mime-db@1.52.0: {}
+ mime-db@1.54.0: {}
+
mime-types@2.1.35:
dependencies:
mime-db: 1.52.0
+ mime-types@3.0.1:
+ dependencies:
+ mime-db: 1.54.0
+
minimatch@3.1.2:
dependencies:
brace-expansion: 1.1.11
@@ -2536,16 +3942,77 @@ snapshots:
mkdirp@3.0.1: {}
+ morgan@1.10.1:
+ dependencies:
+ basic-auth: 2.0.1
+ debug: 2.6.9
+ depd: 2.0.0
+ on-finished: 2.3.0
+ on-headers: 1.1.0
+ transitivePeerDependencies:
+ - supports-color
+
mri@1.2.0: {}
mrmime@2.0.1: {}
+ ms@2.0.0: {}
+
ms@2.1.3: {}
nanoid@3.3.11: {}
natural-compare@1.4.0: {}
+ negotiator@1.0.0: {}
+
+ node-domexception@1.0.0: {}
+
+ node-fetch@3.3.2:
+ dependencies:
+ data-uri-to-buffer: 4.0.1
+ fetch-blob: 3.2.0
+ formdata-polyfill: 4.0.10
+
+ nodemon@3.1.10:
+ dependencies:
+ chokidar: 3.6.0
+ debug: 4.4.1(supports-color@5.5.0)
+ ignore-by-default: 1.0.1
+ minimatch: 3.1.2
+ pstree.remy: 1.1.8
+ semver: 7.7.1
+ simple-update-notifier: 2.0.0
+ supports-color: 5.5.0
+ touch: 3.1.1
+ undefsafe: 2.0.5
+
+ normalize-path@3.0.0: {}
+
+ object-assign@4.1.1: {}
+
+ object-inspect@1.13.4: {}
+
+ on-finished@2.3.0:
+ dependencies:
+ ee-first: 1.1.1
+
+ on-finished@2.4.1:
+ dependencies:
+ ee-first: 1.1.1
+
+ on-headers@1.1.0: {}
+
+ once@1.4.0:
+ dependencies:
+ wrappy: 1.0.2
+
+ one-time@1.0.0:
+ dependencies:
+ fn.name: 1.1.0
+
+ openapi-types@12.1.3: {}
+
optionator@0.9.4:
dependencies:
deep-is: 0.1.4
@@ -2567,14 +4034,22 @@ snapshots:
dependencies:
callsites: 3.1.0
+ parseurl@1.3.3: {}
+
path-exists@4.0.0: {}
+ path-is-absolute@1.0.1: {}
+
path-key@3.1.1: {}
path-parse@1.0.7: {}
+ path-to-regexp@8.2.0: {}
+
picocolors@1.1.1: {}
+ picomatch@2.3.1: {}
+
picomatch@4.0.2: {}
postcss-load-config@3.1.4(postcss@8.5.3):
@@ -2608,35 +4083,68 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
+ postcss@8.5.6:
+ dependencies:
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
prelude-ls@1.2.1: {}
- prettier-plugin-svelte@3.4.0(prettier@3.5.3)(svelte@5.33.18):
+ prettier-plugin-svelte@3.4.0(prettier@3.6.2)(svelte@5.36.14):
dependencies:
- prettier: 3.5.3
- svelte: 5.33.18
+ prettier: 3.6.2
+ svelte: 5.36.14
- prettier-plugin-tailwindcss@0.6.12(prettier-plugin-svelte@3.4.0(prettier@3.5.3)(svelte@5.33.18))(prettier@3.5.3):
+ prettier-plugin-tailwindcss@0.6.14(prettier-plugin-svelte@3.4.0(prettier@3.6.2)(svelte@5.36.14))(prettier@3.6.2):
dependencies:
- prettier: 3.5.3
+ prettier: 3.6.2
optionalDependencies:
- prettier-plugin-svelte: 3.4.0(prettier@3.5.3)(svelte@5.33.18)
+ prettier-plugin-svelte: 3.4.0(prettier@3.6.2)(svelte@5.36.14)
- prettier@3.5.3: {}
+ prettier@3.6.2: {}
- prisma@6.5.0(typescript@5.8.3):
+ prisma@6.12.0(typescript@5.8.3):
dependencies:
- '@prisma/config': 6.5.0
- '@prisma/engines': 6.5.0
+ '@prisma/config': 6.12.0
+ '@prisma/engines': 6.12.0
optionalDependencies:
- fsevents: 2.3.3
typescript: 5.8.3
- transitivePeerDependencies:
- - supports-color
+
+ proxy-addr@2.0.7:
+ dependencies:
+ forwarded: 0.2.0
+ ipaddr.js: 1.9.1
proxy-from-env@1.1.0: {}
+ pstree.remy@1.1.8: {}
+
punycode@2.3.1: {}
+ qs@6.14.0:
+ dependencies:
+ side-channel: 1.1.0
+
+ range-parser@1.2.1: {}
+
+ raw-body@3.0.0:
+ dependencies:
+ bytes: 3.1.2
+ http-errors: 2.0.0
+ iconv-lite: 0.6.3
+ unpipe: 1.0.0
+
+ readable-stream@3.6.2:
+ dependencies:
+ inherits: 2.0.4
+ string_decoder: 1.3.0
+ util-deprecate: 1.0.2
+
+ readdirp@3.6.0:
+ dependencies:
+ picomatch: 2.3.1
+
readdirp@4.1.2: {}
resolve-from@4.0.0: {}
@@ -2673,22 +4181,129 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.39.0
fsevents: 2.3.3
+ rollup@4.45.1:
+ dependencies:
+ '@types/estree': 1.0.8
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.45.1
+ '@rollup/rollup-android-arm64': 4.45.1
+ '@rollup/rollup-darwin-arm64': 4.45.1
+ '@rollup/rollup-darwin-x64': 4.45.1
+ '@rollup/rollup-freebsd-arm64': 4.45.1
+ '@rollup/rollup-freebsd-x64': 4.45.1
+ '@rollup/rollup-linux-arm-gnueabihf': 4.45.1
+ '@rollup/rollup-linux-arm-musleabihf': 4.45.1
+ '@rollup/rollup-linux-arm64-gnu': 4.45.1
+ '@rollup/rollup-linux-arm64-musl': 4.45.1
+ '@rollup/rollup-linux-loongarch64-gnu': 4.45.1
+ '@rollup/rollup-linux-powerpc64le-gnu': 4.45.1
+ '@rollup/rollup-linux-riscv64-gnu': 4.45.1
+ '@rollup/rollup-linux-riscv64-musl': 4.45.1
+ '@rollup/rollup-linux-s390x-gnu': 4.45.1
+ '@rollup/rollup-linux-x64-gnu': 4.45.1
+ '@rollup/rollup-linux-x64-musl': 4.45.1
+ '@rollup/rollup-win32-arm64-msvc': 4.45.1
+ '@rollup/rollup-win32-ia32-msvc': 4.45.1
+ '@rollup/rollup-win32-x64-msvc': 4.45.1
+ fsevents: 2.3.3
+
+ router@2.2.0:
+ dependencies:
+ debug: 4.4.1(supports-color@5.5.0)
+ depd: 2.0.0
+ is-promise: 4.0.0
+ parseurl: 1.3.3
+ path-to-regexp: 8.2.0
+ transitivePeerDependencies:
+ - supports-color
+
sade@1.8.1:
dependencies:
mri: 1.2.0
+ safe-buffer@5.1.2: {}
+
+ safe-buffer@5.2.1: {}
+
+ safe-stable-stringify@2.5.0: {}
+
+ safer-buffer@2.1.2: {}
+
schema-dts@1.1.5: {}
semver@7.7.1: {}
+ send@1.2.0:
+ dependencies:
+ debug: 4.4.1(supports-color@5.5.0)
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ etag: 1.8.1
+ fresh: 2.0.0
+ http-errors: 2.0.0
+ mime-types: 3.0.1
+ ms: 2.1.3
+ on-finished: 2.4.1
+ range-parser: 1.2.1
+ statuses: 2.0.2
+ transitivePeerDependencies:
+ - supports-color
+
+ serve-static@2.2.0:
+ dependencies:
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ parseurl: 1.3.3
+ send: 1.2.0
+ transitivePeerDependencies:
+ - supports-color
+
set-cookie-parser@2.7.1: {}
+ setprototypeof@1.2.0: {}
+
shebang-command@2.0.0:
dependencies:
shebang-regex: 3.0.0
shebang-regex@3.0.0: {}
+ side-channel-list@1.0.0:
+ dependencies:
+ es-errors: 1.3.0
+ object-inspect: 1.13.4
+
+ side-channel-map@1.0.1:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ object-inspect: 1.13.4
+
+ side-channel-weakmap@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ object-inspect: 1.13.4
+ side-channel-map: 1.0.1
+
+ side-channel@1.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ object-inspect: 1.13.4
+ side-channel-list: 1.0.0
+ side-channel-map: 1.0.1
+ side-channel-weakmap: 1.0.2
+
+ simple-swizzle@0.2.2:
+ dependencies:
+ is-arrayish: 0.3.2
+
+ simple-update-notifier@2.0.0:
+ dependencies:
+ semver: 7.7.1
+
sirv@3.0.1:
dependencies:
'@polka/url': 1.0.0-next.29
@@ -2697,31 +4312,45 @@ snapshots:
source-map-js@1.2.1: {}
+ stack-trace@0.0.10: {}
+
+ statuses@2.0.1: {}
+
+ statuses@2.0.2: {}
+
+ string_decoder@1.3.0:
+ dependencies:
+ safe-buffer: 5.2.1
+
strip-json-comments@3.1.1: {}
+ supports-color@5.5.0:
+ dependencies:
+ has-flag: 3.0.0
+
supports-color@7.2.0:
dependencies:
has-flag: 4.0.0
supports-preserve-symlinks-flag@1.0.0: {}
- svelte-check@4.2.1(picomatch@4.0.2)(svelte@5.33.18)(typescript@5.8.3):
+ svelte-check@4.3.0(picomatch@4.0.2)(svelte@5.36.14)(typescript@5.8.3):
dependencies:
'@jridgewell/trace-mapping': 0.3.25
chokidar: 4.0.3
- fdir: 6.4.3(picomatch@4.0.2)
+ fdir: 6.4.6(picomatch@4.0.2)
picocolors: 1.1.1
sade: 1.8.1
- svelte: 5.33.18
+ svelte: 5.36.14
typescript: 5.8.3
transitivePeerDependencies:
- picomatch
- svelte-dnd-action@0.9.61(svelte@5.33.18):
+ svelte-dnd-action@0.9.64(svelte@5.36.14):
dependencies:
- svelte: 5.33.18
+ svelte: 5.36.14
- svelte-eslint-parser@1.2.0(svelte@5.33.18):
+ svelte-eslint-parser@1.3.0(svelte@5.36.14):
dependencies:
eslint-scope: 8.3.0
eslint-visitor-keys: 4.2.0
@@ -2730,18 +4359,18 @@ snapshots:
postcss-scss: 4.0.9(postcss@8.5.3)
postcss-selector-parser: 7.1.0
optionalDependencies:
- svelte: 5.33.18
+ svelte: 5.36.14
svelte-highlight@7.8.3:
dependencies:
highlight.js: 11.11.1
- svelte-meta-tags@4.4.0(svelte@5.33.18):
+ svelte-meta-tags@4.4.0(svelte@5.36.14):
dependencies:
schema-dts: 1.1.5
- svelte: 5.33.18
+ svelte: 5.36.14
- svelte@5.33.18:
+ svelte@5.36.14:
dependencies:
'@ampproject/remapping': 2.3.0
'@jridgewell/sourcemap-codec': 1.5.0
@@ -2752,13 +4381,39 @@ snapshots:
axobject-query: 4.1.0
clsx: 2.1.1
esm-env: 1.2.2
- esrap: 1.4.9
+ esrap: 2.1.0
is-reference: 3.0.3
locate-character: 3.0.0
magic-string: 0.30.17
zimmerframe: 1.1.2
- tailwindcss@4.1.8: {}
+ swagger-jsdoc@6.2.8(openapi-types@12.1.3):
+ dependencies:
+ commander: 6.2.0
+ doctrine: 3.0.0
+ glob: 7.1.6
+ lodash.mergewith: 4.6.2
+ swagger-parser: 10.0.3(openapi-types@12.1.3)
+ yaml: 2.0.0-1
+ transitivePeerDependencies:
+ - openapi-types
+
+ swagger-parser@10.0.3(openapi-types@12.1.3):
+ dependencies:
+ '@apidevtools/swagger-parser': 10.0.3(openapi-types@12.1.3)
+ transitivePeerDependencies:
+ - openapi-types
+
+ swagger-ui-dist@5.27.0:
+ dependencies:
+ '@scarf/scarf': 1.4.0
+
+ swagger-ui-express@5.0.1(express@5.1.0):
+ dependencies:
+ express: 5.1.0
+ swagger-ui-dist: 5.27.0
+
+ tailwindcss@4.1.11: {}
tapable@2.2.1: {}
@@ -2771,19 +4426,43 @@ snapshots:
mkdirp: 3.0.1
yallist: 5.0.0
+ text-hex@1.0.0: {}
+
tinyglobby@0.2.14:
dependencies:
fdir: 6.4.6(picomatch@4.0.2)
picomatch: 4.0.2
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
+ toidentifier@1.0.1: {}
+
totalist@3.0.1: {}
+ touch@3.1.1: {}
+
+ triple-beam@1.4.1: {}
+
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1
+ type-is@2.0.1:
+ dependencies:
+ content-type: 1.0.5
+ media-typer: 1.1.0
+ mime-types: 3.0.1
+
typescript@5.8.3: {}
+ undefsafe@2.0.5: {}
+
+ undici-types@7.8.0: {}
+
+ unpipe@1.0.0: {}
+
uri-js@4.4.1:
dependencies:
punycode: 2.3.1
@@ -2792,35 +4471,74 @@ snapshots:
uuid@11.1.0: {}
- vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1):
+ validator@13.15.15: {}
+
+ vary@1.1.2: {}
+
+ vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1):
dependencies:
esbuild: 0.25.2
fdir: 6.4.6(picomatch@4.0.2)
picomatch: 4.0.2
- postcss: 8.5.3
- rollup: 4.39.0
+ postcss: 8.5.6
+ rollup: 4.45.1
tinyglobby: 0.2.14
optionalDependencies:
+ '@types/node': 24.1.0
fsevents: 2.3.3
jiti: 2.4.2
lightningcss: 1.30.1
- vitefu@1.0.6(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)):
+ vitefu@1.1.1(vite@7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1)):
optionalDependencies:
- vite: 6.3.5(jiti@2.4.2)(lightningcss@1.30.1)
+ vite: 7.0.5(@types/node@24.1.0)(jiti@2.4.2)(lightningcss@1.30.1)
+
+ web-streams-polyfill@3.3.3: {}
which@2.0.2:
dependencies:
isexe: 2.0.0
+ winston-transport@4.9.0:
+ dependencies:
+ logform: 2.7.0
+ readable-stream: 3.6.2
+ triple-beam: 1.4.1
+
+ winston@3.17.0:
+ dependencies:
+ '@colors/colors': 1.6.0
+ '@dabh/diagnostics': 2.0.3
+ async: 3.2.6
+ is-stream: 2.0.1
+ logform: 2.7.0
+ one-time: 1.0.0
+ readable-stream: 3.6.2
+ safe-stable-stringify: 2.5.0
+ stack-trace: 0.0.10
+ triple-beam: 1.4.1
+ winston-transport: 4.9.0
+
word-wrap@1.2.5: {}
+ wrappy@1.0.2: {}
+
yallist@5.0.0: {}
yaml@1.10.2: {}
+ yaml@2.0.0-1: {}
+
yocto-queue@0.1.0: {}
+ z-schema@5.0.5:
+ dependencies:
+ lodash.get: 4.4.2
+ lodash.isequal: 4.5.0
+ validator: 13.15.15
+ optionalDependencies:
+ commander: 9.5.0
+
zimmerframe@1.1.2: {}
- zod@3.25.57: {}
+ zod@4.0.8: {}
diff --git a/prisma/migrations/20250730175647_add_jwt_token_model/migration.sql b/prisma/migrations/20250730175647_add_jwt_token_model/migration.sql
new file mode 100644
index 0000000..0440d5a
--- /dev/null
+++ b/prisma/migrations/20250730175647_add_jwt_token_model/migration.sql
@@ -0,0 +1,30 @@
+-- CreateTable
+CREATE TABLE "JwtToken" (
+ "id" TEXT NOT NULL,
+ "token" TEXT NOT NULL,
+ "userId" TEXT NOT NULL,
+ "expiresAt" TIMESTAMP(3) NOT NULL,
+ "isRevoked" BOOLEAN NOT NULL DEFAULT false,
+ "deviceInfo" TEXT,
+ "ipAddress" TEXT,
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" TIMESTAMP(3) NOT NULL,
+ "lastUsedAt" TIMESTAMP(3),
+
+ CONSTRAINT "JwtToken_pkey" PRIMARY KEY ("id")
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "JwtToken_token_key" ON "JwtToken"("token");
+
+-- CreateIndex
+CREATE INDEX "JwtToken_userId_idx" ON "JwtToken"("userId");
+
+-- CreateIndex
+CREATE INDEX "JwtToken_expiresAt_idx" ON "JwtToken"("expiresAt");
+
+-- CreateIndex
+CREATE INDEX "JwtToken_isRevoked_idx" ON "JwtToken"("isRevoked");
+
+-- AddForeignKey
+ALTER TABLE "JwtToken" ADD CONSTRAINT "JwtToken_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml
index 648c57f..044d57c 100644
--- a/prisma/migrations/migration_lock.toml
+++ b/prisma/migrations/migration_lock.toml
@@ -1,3 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
-provider = "postgresql"
\ No newline at end of file
+provider = "postgresql"
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index d12c2f0..7b57a4e 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -43,6 +43,25 @@ model User {
BoardTask BoardTask[]
BoardTaskActivity BoardTaskActivity[]
BlogPost BlogPost[]
+ jwtTokens JwtToken[]
+}
+
+model JwtToken {
+ id String @id @default(uuid())
+ token String @unique
+ userId String
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
+ expiresAt DateTime
+ isRevoked Boolean @default(false)
+ deviceInfo String? // Optional: store device/client info
+ ipAddress String? // Optional: store IP address
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ lastUsedAt DateTime?
+
+ @@index([userId])
+ @@index([expiresAt])
+ @@index([isRevoked])
}
model Organization {
diff --git a/server.js b/server.js
new file mode 100644
index 0000000..3ccacfa
--- /dev/null
+++ b/server.js
@@ -0,0 +1,100 @@
+import express from 'express';
+import cors from 'cors';
+import helmet from 'helmet';
+import rateLimit from 'express-rate-limit';
+import swaggerJsdoc from 'swagger-jsdoc';
+import swaggerUi from 'swagger-ui-express';
+import dotenv from 'dotenv';
+import { createLogger } from './api/config/logger.js';
+import { requestLogger } from './api/middleware/requestLogger.js';
+import { errorHandler } from './api/middleware/errorHandler.js';
+import authRoutes from './api/routes/auth.js';
+import dashboardRoutes from './api/routes/dashboard.js';
+import leadRoutes from './api/routes/leads.js';
+import accountRoutes from './api/routes/accounts.js';
+import contactRoutes from './api/routes/contacts.js';
+import opportunityRoutes from './api/routes/opportunities.js';
+import taskRoutes from './api/routes/tasks.js';
+
+dotenv.config();
+
+const app = express();
+const logger = createLogger();
+const PORT = process.env.API_PORT || 3001;
+
+// Trust proxy setting for rate limiting
+app.set('trust proxy', 1);
+
+const rateLimiter = rateLimit({
+ windowMs: 15 * 60 * 1000, // 15 minutes
+ max: 100,
+ message: 'Too many requests from this IP, please try again later.',
+});
+
+const swaggerOptions = {
+ definition: {
+ openapi: '3.0.0',
+ info: {
+ title: 'BottleCRM API',
+ version: '1.0.0',
+ description: 'Multi-tenant CRM API with JWT authentication',
+ },
+ servers: [
+ {
+ url: `http://localhost:${PORT}`,
+ description: 'Development server',
+ },
+ ],
+ components: {
+ securitySchemes: {
+ bearerAuth: {
+ type: 'http',
+ scheme: 'bearer',
+ bearerFormat: 'JWT',
+ },
+ },
+ },
+ security: [
+ {
+ bearerAuth: [],
+ },
+ ],
+ },
+ apis: ['./api/routes/*.js'],
+};
+
+const specs = swaggerJsdoc(swaggerOptions);
+
+app.use(helmet());
+app.use(cors({
+ origin: process.env.FRONTEND_URL || 'http://localhost:5173',
+ credentials: true,
+}));
+app.use(rateLimiter);
+app.use(express.json({ limit: '10mb' }));
+app.use(express.urlencoded({ extended: true }));
+
+app.use(requestLogger);
+
+app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs));
+
+app.use('/auth', authRoutes);
+app.use('/dashboard', dashboardRoutes);
+app.use('/leads', leadRoutes);
+app.use('/accounts', accountRoutes);
+app.use('/contacts', contactRoutes);
+app.use('/opportunities', opportunityRoutes);
+app.use('/tasks', taskRoutes);
+
+app.get('/health', (req, res) => {
+ res.json({ status: 'OK', timestamp: new Date().toISOString() });
+});
+
+app.use(errorHandler);
+
+app.listen(PORT, () => {
+ logger.info(`BottleCRM API server running on port ${PORT}`);
+ logger.info(`Swagger documentation available at http://localhost:${PORT}/api-docs`);
+});
+
+export default app;
\ No newline at end of file
diff --git a/static/funding.json b/static/funding.json
new file mode 100644
index 0000000..b7b663a
--- /dev/null
+++ b/static/funding.json
@@ -0,0 +1,99 @@
+{
+ "version": "v1.0.0",
+
+ "entity": {
+ "type": "organisation",
+ "role": "owner",
+ "name": "MicroPyramid Informatics Private Limited",
+ "email": "hello@micropyramid.com",
+ "phone": "+91-9959166266",
+ "description": "MicroPyramid is a technology company specializing in web development, mobile applications, and SaaS solutions. We build modern, scalable software solutions for businesses of all sizes, with expertise in Python, Django, React, and other cutting-edge technologies.",
+ "webpageUrl": {
+ "url": "https://micropyramid.com",
+ "wellKnown": ""
+ }
+ },
+
+ "projects": [{
+ "guid": "startup-crm",
+ "name": "BottleCRM",
+ "description": "BottleCRM is a dynamic, SaaS CRM platform designed to streamline the entire CRM needs of startups and enterprises. Built with modern web technologies including SvelteKit, Svelte 5, and Prisma, it offers a seamless experience for users through robust role-based access control (RBAC). Each user role is equipped with tailored functionalities to enhance efficiency, engagement, and management, ensuring a streamlined and secure business process.",
+ "webpageUrl": {
+ "url": "https://bottlecrm.io",
+ "wellKnown": ""
+ },
+ "repositoryUrl": {
+ "url": "https://github.com/MicroPyramid/opensource-startup-crm",
+ "wellKnown": ""
+ },
+ "licenses": ["spdx:MIT"],
+ "tags": ["crm", "saas", "business-tools", "customer-management", "sales", "svelte", "typescript", "web-application", "enterprise", "startup"]
+ }],
+
+ "funding": {
+ "channels": [{
+ "guid": "paypal",
+ "type": "payment-provider",
+ "address": "paypal@micropyramid.com",
+ "description": "PayPal payments for international transactions"
+ }, {
+ "guid": "bank-transfer",
+ "type": "bank",
+ "address": "Contact hello@micropyramid.com for bank details",
+ "description": "Direct bank transfers for larger contributions"
+ }, {
+ "guid": "github-sponsors",
+ "type": "payment-provider",
+ "address": "https://github.com/sponsors/micropyramid",
+ "description": "GitHub Sponsors for recurring monthly support"
+ }],
+
+ "plans": [{
+ "guid": "monthly-supporter",
+ "status": "active",
+ "name": "Monthly Supporter",
+ "description": "Monthly support to help maintain and improve BottleCRM with regular updates, bug fixes, and new features.",
+ "amount": 25,
+ "currency": "USD",
+ "frequency": "monthly",
+ "channels": ["paypal", "github-sponsors"]
+ }, {
+ "guid": "yearly-backer",
+ "status": "active",
+ "name": "Yearly Backer",
+ "description": "Annual support for sustained development and maintenance of BottleCRM platform.",
+ "amount": 250,
+ "currency": "USD",
+ "frequency": "yearly",
+ "channels": ["paypal", "bank-transfer", "github-sponsors"]
+ }, {
+ "guid": "enterprise-sponsor",
+ "status": "active",
+ "name": "Enterprise Sponsor",
+ "description": "Enterprise-level sponsorship for priority support, custom features, and dedicated development resources.",
+ "amount": 1000,
+ "currency": "USD",
+ "frequency": "monthly",
+ "channels": ["bank-transfer", "paypal"]
+ }, {
+ "guid": "one-time-donation",
+ "status": "active",
+ "name": "One-time Contribution",
+ "description": "One-time donation to support BottleCRM development. Any amount is appreciated.",
+ "amount": 0,
+ "currency": "USD",
+ "frequency": "one-time",
+ "channels": ["paypal", "github-sponsors"]
+ }],
+
+ "history": [{
+ "year": 2025,
+ "income": 0,
+ "expenses": 5000,
+ "taxes": 0,
+ "currency": "USD",
+ "description": "Initial development phase with investment in infrastructure, development tools, and hosting."
+ }]
+ }
+}
+