Compare commits
10 Commits
1c6dfc4f8b
...
23c1d33adb
| Author | SHA1 | Date |
|---|---|---|
|
|
23c1d33adb | |
|
|
a8220921cb | |
|
|
ba85b076ad | |
|
|
f938c63cf6 | |
|
|
bf96452f1b | |
|
|
8b68d8a5cf | |
|
|
bb15bfef28 | |
|
|
405ffafe11 | |
|
|
684a010537 | |
|
|
f724a71ade |
|
|
@ -0,0 +1,79 @@
|
||||||
|
# Dependencies
|
||||||
|
node_modules
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# Build outputs
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Environment files
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.docker
|
||||||
|
|
||||||
|
# IDE files
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# OS generated files
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
._*
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
ehthumbs.db
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Coverage directory
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Git
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
Dockerfile*
|
||||||
|
docker-compose*
|
||||||
|
.dockerignore
|
||||||
|
|
||||||
|
# Data directories (will be mounted as volumes)
|
||||||
|
data
|
||||||
|
uploads
|
||||||
|
results
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
temp
|
||||||
|
tmp
|
||||||
|
|
||||||
|
# Test files
|
||||||
|
tests
|
||||||
|
test-*.sh
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
README.md
|
||||||
|
docs
|
||||||
|
infrastructure.md
|
||||||
|
|
||||||
|
# Other
|
||||||
|
.claude
|
||||||
|
.mcp.json
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Application Configuration
|
||||||
|
NODE_ENV=development
|
||||||
|
PORT=3000
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
|
# CORS Configuration
|
||||||
|
CORS_ORIGIN=*
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
DB_HOST=postgres
|
||||||
|
DB_PORT=5432
|
||||||
|
DB_NAME=banatie_db
|
||||||
|
DB_USER=banatie_user
|
||||||
|
DB_PASSWORD=development_password
|
||||||
|
|
||||||
|
# MinIO Storage Configuration
|
||||||
|
STORAGE_TYPE=minio
|
||||||
|
MINIO_ENDPOINT=minio:9000
|
||||||
|
MINIO_ACCESS_KEY=minioadmin
|
||||||
|
MINIO_SECRET_KEY=minioadmin
|
||||||
|
MINIO_USE_SSL=false
|
||||||
|
MINIO_BUCKET_PREFIX=banatie
|
||||||
|
MINIO_PUBLIC_URL=http://localhost:9000
|
||||||
|
|
||||||
|
# AI Service Configuration (using the existing API key from .env)
|
||||||
|
GEMINI_API_KEY=AIzaSyBaOt9JMPGKA3811FL-ssf1n5Hh9Jauly8
|
||||||
|
|
||||||
|
# File Upload Configuration
|
||||||
|
MAX_FILE_SIZE=5242880
|
||||||
|
MAX_FILES=3
|
||||||
|
|
||||||
|
# Multi-tenancy Configuration
|
||||||
|
DEFAULT_ORG_ID=demo
|
||||||
|
DEFAULT_USER_ID=guest
|
||||||
|
|
||||||
|
# Directory Configuration (for Docker containers)
|
||||||
|
RESULTS_DIR=/app/results
|
||||||
|
UPLOADS_DIR=/app/uploads/temp
|
||||||
|
|
||||||
|
# Logging Configuration
|
||||||
|
LOG_LEVEL=info
|
||||||
|
|
@ -77,4 +77,13 @@ uploads/
|
||||||
|
|
||||||
# Temporary files
|
# Temporary files
|
||||||
temp/
|
temp/
|
||||||
tmp/
|
tmp/
|
||||||
|
|
||||||
|
# Docker data directories
|
||||||
|
data/
|
||||||
|
.env.docker
|
||||||
|
.env.production
|
||||||
|
|
||||||
|
# Docker volumes (persistent data)
|
||||||
|
postgres-data/
|
||||||
|
minio-data/
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"context7": {
|
||||||
|
"type": "stdio",
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"@upstash/context7-mcp",
|
||||||
|
"--api-key",
|
||||||
|
"ctx7sk-48cb1995-935a-4cc5-b9b0-535d600ea5e6"
|
||||||
|
],
|
||||||
|
"env": {}
|
||||||
|
},
|
||||||
|
"brave-search": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"@modelcontextprotocol/server-brave-search"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"BRAVE_API_KEY": "BSAcRGGikEzY4B2j3NZ8Qy5NYh9l4HZ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"postgres": {
|
||||||
|
"command": "docker",
|
||||||
|
"args": ["run", "-i", "--rm", "-e", "DATABASE_URI", "crystaldba/postgres-mcp", "--access-mode=unrestricted"],
|
||||||
|
"env": {
|
||||||
|
"DATABASE_URI": "postgresql://postgres:postgres@localhost:5433/prime_db"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mastra": {
|
||||||
|
"type": "stdio",
|
||||||
|
"command": "npx",
|
||||||
|
"args": ["@mastra/mcp-docs-server@latest"],
|
||||||
|
"env": {}
|
||||||
|
},
|
||||||
|
"browsermcp": {
|
||||||
|
"type": "stdio",
|
||||||
|
"command": "npx",
|
||||||
|
"args": ["-y", "@browsermcp/mcp@latest"],
|
||||||
|
"env": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
# Development stage - for docker-compose development with hot reload
|
||||||
|
FROM node:20-alpine AS development
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install pnpm globally
|
||||||
|
RUN npm install -g pnpm
|
||||||
|
|
||||||
|
# Copy package files for dependency installation
|
||||||
|
COPY package*.json pnpm-lock.yaml ./
|
||||||
|
RUN pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
# Copy source code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
# Use development command with hot reload
|
||||||
|
CMD ["pnpm", "dev"]
|
||||||
|
|
||||||
|
# Builder stage - for production build
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install pnpm globally
|
||||||
|
RUN npm install -g pnpm
|
||||||
|
|
||||||
|
# Copy package files
|
||||||
|
COPY package*.json pnpm-lock.yaml ./
|
||||||
|
|
||||||
|
# Install all dependencies (including dev dependencies for build)
|
||||||
|
RUN pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
# Copy source code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build TypeScript to JavaScript
|
||||||
|
RUN pnpm build
|
||||||
|
|
||||||
|
# Production stage - optimized final image
|
||||||
|
FROM node:20-alpine AS production
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Create non-root user for security
|
||||||
|
RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001
|
||||||
|
|
||||||
|
# Install pnpm globally
|
||||||
|
RUN npm install -g pnpm
|
||||||
|
|
||||||
|
# Copy package files
|
||||||
|
COPY --from=builder /app/package*.json ./
|
||||||
|
COPY --from=builder /app/pnpm-lock.yaml ./
|
||||||
|
|
||||||
|
# Install only production dependencies
|
||||||
|
RUN pnpm install --prod --frozen-lockfile
|
||||||
|
|
||||||
|
# Copy built application
|
||||||
|
COPY --from=builder /app/dist ./dist
|
||||||
|
|
||||||
|
# Create required directories and set ownership
|
||||||
|
RUN mkdir -p logs && chown -R nodejs:nodejs /app
|
||||||
|
|
||||||
|
# Switch to non-root user
|
||||||
|
USER nodejs
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||||
|
CMD node -e "require('http').request('http://localhost:3000/health', (res) => { \
|
||||||
|
process.exit(res.statusCode === 200 ? 0 : 1) \
|
||||||
|
}).on('error', () => process.exit(1)).end()"
|
||||||
|
|
||||||
|
# Start the application
|
||||||
|
CMD ["node", "dist/server.js"]
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
target: development
|
||||||
|
container_name: banatie-app-dev
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
volumes:
|
||||||
|
- ./src:/app/src # Hot reload for development
|
||||||
|
- ./logs:/app/logs # Persistent logs
|
||||||
|
networks:
|
||||||
|
- banatie-dev
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
minio:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=development
|
||||||
|
env_file:
|
||||||
|
- .env.docker
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
container_name: banatie-postgres-dev
|
||||||
|
ports:
|
||||||
|
- "5434:5432" # Avoid conflicts with other PostgreSQL instances
|
||||||
|
volumes:
|
||||||
|
- ./data/postgres:/var/lib/postgresql/data
|
||||||
|
- ./scripts/init-db.sql:/docker-entrypoint-initdb.d/01-init.sql
|
||||||
|
networks:
|
||||||
|
- banatie-dev
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: banatie_db
|
||||||
|
POSTGRES_USER: banatie_user
|
||||||
|
POSTGRES_PASSWORD: development_password
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U banatie_user -d banatie_db"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
minio:
|
||||||
|
image: minio/minio:latest
|
||||||
|
container_name: banatie-minio-dev
|
||||||
|
ports:
|
||||||
|
- "9000:9000" # S3 API
|
||||||
|
- "9001:9001" # Web Console
|
||||||
|
volumes:
|
||||||
|
- ./data/minio:/data
|
||||||
|
networks:
|
||||||
|
- banatie-dev
|
||||||
|
environment:
|
||||||
|
MINIO_ROOT_USER: minioadmin
|
||||||
|
MINIO_ROOT_PASSWORD: minioadmin
|
||||||
|
command: server /data --console-address ":9001"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
minio-init:
|
||||||
|
image: minio/mc:latest
|
||||||
|
container_name: banatie-minio-init
|
||||||
|
networks:
|
||||||
|
- banatie-dev
|
||||||
|
depends_on:
|
||||||
|
minio:
|
||||||
|
condition: service_healthy
|
||||||
|
entrypoint: >
|
||||||
|
/bin/sh -c "
|
||||||
|
echo 'Setting up MinIO alias...';
|
||||||
|
mc alias set minio http://minio:9000 minioadmin minioadmin;
|
||||||
|
|
||||||
|
echo 'Creating demo bucket...';
|
||||||
|
mc mb --ignore-existing minio/banatie-demo;
|
||||||
|
|
||||||
|
echo 'Setting up public read policy for generated images...';
|
||||||
|
mc anonymous set download minio/banatie-demo/users/guest/generated;
|
||||||
|
|
||||||
|
echo 'Creating banatie service user...';
|
||||||
|
mc admin user add minio banatie-user banatie-password;
|
||||||
|
|
||||||
|
echo 'Attaching readwrite policy to banatie user...';
|
||||||
|
mc admin policy attach minio readwrite --user=banatie-user;
|
||||||
|
|
||||||
|
echo 'Creating lifecycle policy for temp files (7 days retention)...';
|
||||||
|
cat > /tmp/lifecycle.json << EOF
|
||||||
|
{
|
||||||
|
\"Rules\": [
|
||||||
|
{
|
||||||
|
\"ID\": \"temp-files-cleanup\",
|
||||||
|
\"Status\": \"Enabled\",
|
||||||
|
\"Filter\": {
|
||||||
|
\"Prefix\": \"users/\"
|
||||||
|
},
|
||||||
|
\"Expiration\": {
|
||||||
|
\"Days\": 7
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
mc ilm import minio/banatie-demo < /tmp/lifecycle.json;
|
||||||
|
|
||||||
|
echo 'MinIO initialization completed successfully!';
|
||||||
|
exit 0;
|
||||||
|
"
|
||||||
|
restart: "no"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
banatie-dev:
|
||||||
|
driver: bridge
|
||||||
|
name: banatie-dev-network
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres-data:
|
||||||
|
driver: local
|
||||||
|
minio-data:
|
||||||
|
driver: local
|
||||||
|
|
@ -0,0 +1,937 @@
|
||||||
|
# Banatie Service Infrastructure Documentation
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document defines the complete containerization and deployment architecture for the Banatie AI image generation service with MinIO object storage and PostgreSQL database integration.
|
||||||
|
|
||||||
|
## Architecture Summary
|
||||||
|
|
||||||
|
### Core Principles
|
||||||
|
- **Complete Service Isolation**: Banatie ecosystem is fully isolated from core VPS services
|
||||||
|
- **Dedicated Database**: Separate PostgreSQL container exclusively for Banatie
|
||||||
|
- **S3-Compatible Storage**: MinIO for scalable object storage with multi-tenant support
|
||||||
|
- **Container-First Approach**: All components run as Docker containers
|
||||||
|
- **Network Segregation**: Internal communication via dedicated Docker networks
|
||||||
|
|
||||||
|
### Service Components
|
||||||
|
|
||||||
|
```
|
||||||
|
Banatie Ecosystem (Isolated)
|
||||||
|
├── Banatie App Container (Node.js/TypeScript/Express)
|
||||||
|
├── PostgreSQL Container (Dedicated instance)
|
||||||
|
└── MinIO Container (S3-compatible object storage)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Network Architecture
|
||||||
|
|
||||||
|
### Production Networks
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
networks:
|
||||||
|
banatie-network:
|
||||||
|
driver: bridge
|
||||||
|
internal: true # No external internet access
|
||||||
|
|
||||||
|
proxy-network:
|
||||||
|
external: true # Existing Caddy reverse proxy network
|
||||||
|
```
|
||||||
|
|
||||||
|
### Network Access Matrix
|
||||||
|
|
||||||
|
| Service | banatie-network | proxy-network | External Access |
|
||||||
|
|---------|----------------|---------------|-----------------|
|
||||||
|
| Banatie App | ✅ Internal | ✅ HTTP only | ❌ Direct |
|
||||||
|
| PostgreSQL | ✅ Internal | ❌ None | ❌ None |
|
||||||
|
| MinIO | ✅ Internal | ✅ Console only | ❌ Direct |
|
||||||
|
| Caddy Proxy | ❌ None | ✅ Routing | ✅ Internet |
|
||||||
|
|
||||||
|
### VPS Integration Points
|
||||||
|
|
||||||
|
**Isolation from Core Services:**
|
||||||
|
- **NO** shared resources with existing PostgreSQL (`/opt/services/`)
|
||||||
|
- **NO** access to NextCloud, Gitea, or other core services
|
||||||
|
- **ONLY** connection point: Caddy reverse proxy for HTTP routing
|
||||||
|
|
||||||
|
**Shared Infrastructure:**
|
||||||
|
- Caddy reverse proxy for SSL termination and routing
|
||||||
|
- Host filesystem for persistent data storage
|
||||||
|
- UFW firewall rules and security policies
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
### Development Environment
|
||||||
|
```
|
||||||
|
banatie-service/
|
||||||
|
├── src/ # Application source code
|
||||||
|
├── Dockerfile # Multi-stage container build
|
||||||
|
├── docker-compose.yml # Local development setup
|
||||||
|
├── .env.example # Environment template
|
||||||
|
├── .dockerignore # Build exclusions
|
||||||
|
└── data/ # Local development data
|
||||||
|
├── postgres/ # PostgreSQL data
|
||||||
|
└── minio/ # MinIO data
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production Environment (VPS)
|
||||||
|
```
|
||||||
|
/opt/banatie/ # Isolated deployment directory
|
||||||
|
├── docker-compose.yml # Production configuration
|
||||||
|
├── .env # Production environment (secure)
|
||||||
|
├── Dockerfile # Production Dockerfile
|
||||||
|
├── data/ # Persistent data storage
|
||||||
|
│ ├── postgres/ # PostgreSQL data
|
||||||
|
│ └── minio/ # MinIO data
|
||||||
|
├── configs/ # Service configurations
|
||||||
|
├── logs/ # Application logs
|
||||||
|
└── scripts/ # Deployment scripts
|
||||||
|
```
|
||||||
|
|
||||||
|
## Container Specifications
|
||||||
|
|
||||||
|
### 1. Banatie Application Container
|
||||||
|
|
||||||
|
**Base Image**: `node:20-alpine`
|
||||||
|
**Build Strategy**: Multi-stage for optimization
|
||||||
|
**Runtime**: Node.js with TypeScript compilation
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
# Multi-stage build for production
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package*.json pnpm-lock.yaml ./
|
||||||
|
RUN npm install -g pnpm && pnpm install --frozen-lockfile
|
||||||
|
COPY . .
|
||||||
|
RUN pnpm build
|
||||||
|
|
||||||
|
FROM node:20-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
RUN npm install -g pnpm
|
||||||
|
COPY --from=builder /app/dist ./dist
|
||||||
|
COPY --from=builder /app/package*.json ./
|
||||||
|
COPY --from=builder /app/pnpm-lock.yaml ./
|
||||||
|
RUN pnpm install --prod --frozen-lockfile
|
||||||
|
EXPOSE 3000
|
||||||
|
CMD ["node", "dist/server.js"]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key Features:**
|
||||||
|
- Hot-reload support in development
|
||||||
|
- Production-optimized build with dependencies pruning
|
||||||
|
- Health check endpoints for monitoring
|
||||||
|
- Structured logging to stdout
|
||||||
|
|
||||||
|
### 2. PostgreSQL Container
|
||||||
|
|
||||||
|
**Image**: `postgres:15-alpine`
|
||||||
|
**Purpose**: Metadata storage for user sessions, image metadata, organization data
|
||||||
|
**Data**: User accounts, image metadata, upload sessions, organization settings
|
||||||
|
|
||||||
|
**Database Schema:**
|
||||||
|
- `users` - User authentication and profiles
|
||||||
|
- `organizations` - Multi-tenant organization data
|
||||||
|
- `images` - Generated image metadata and references
|
||||||
|
- `sessions` - User session management
|
||||||
|
- `uploads` - Temporary upload tracking
|
||||||
|
|
||||||
|
### 3. MinIO Container
|
||||||
|
|
||||||
|
**Image**: `minio/minio:latest`
|
||||||
|
**Purpose**: S3-compatible object storage for images and files
|
||||||
|
**Ports**: 9000 (S3 API), 9001 (Web Console)
|
||||||
|
|
||||||
|
**Storage Strategy:**
|
||||||
|
- Persistent volumes for data durability
|
||||||
|
- Bucket-per-organization architecture
|
||||||
|
- Lifecycle policies for temporary file cleanup
|
||||||
|
- Presigned URLs for direct browser uploads
|
||||||
|
|
||||||
|
## Multi-Tenant Storage Architecture
|
||||||
|
|
||||||
|
### MinIO Bucket Organization
|
||||||
|
|
||||||
|
```
|
||||||
|
banatie-{org-id}/ # Organization bucket (e.g., banatie-demo)
|
||||||
|
├── users/
|
||||||
|
│ └── {user-id}/ # User-specific namespace
|
||||||
|
│ ├── generated/ # AI-generated images
|
||||||
|
│ │ ├── 2024/01/ # Date-based organization
|
||||||
|
│ │ └── thumbnails/ # Generated thumbnails
|
||||||
|
│ ├── references/ # User-uploaded reference images
|
||||||
|
│ └── temp/ # Temporary processing files (7-day TTL)
|
||||||
|
├── shared/ # Organization-wide shared resources
|
||||||
|
│ ├── templates/ # Shared image templates
|
||||||
|
│ └── public/ # Public organization assets
|
||||||
|
└── metadata/ # JSON metadata files
|
||||||
|
├── users.json # User directory metadata
|
||||||
|
└── policies.json # Access control policies
|
||||||
|
```
|
||||||
|
|
||||||
|
### Demo Organization Setup
|
||||||
|
|
||||||
|
**Default Configuration:**
|
||||||
|
- **Organization**: `demo` (org-id: demo)
|
||||||
|
- **User**: `guest` (user-id: guest)
|
||||||
|
- **Bucket**: `banatie-demo`
|
||||||
|
- **Access**: Public read for demo images
|
||||||
|
|
||||||
|
**Demo Bucket Structure:**
|
||||||
|
```
|
||||||
|
banatie-demo/
|
||||||
|
├── users/
|
||||||
|
│ └── guest/
|
||||||
|
│ ├── generated/ # Guest user's generated images
|
||||||
|
│ └── references/ # Guest user's reference uploads
|
||||||
|
└── shared/
|
||||||
|
└── examples/ # Example images for UI
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment Configuration
|
||||||
|
|
||||||
|
### Development Environment (.env)
|
||||||
|
|
||||||
|
```env
|
||||||
|
# Application Configuration
|
||||||
|
NODE_ENV=development
|
||||||
|
PORT=3000
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
DB_HOST=postgres
|
||||||
|
DB_PORT=5432
|
||||||
|
DB_NAME=banatie_db
|
||||||
|
DB_USER=banatie_user
|
||||||
|
DB_PASSWORD=development_password
|
||||||
|
|
||||||
|
# MinIO Configuration
|
||||||
|
STORAGE_TYPE=minio
|
||||||
|
MINIO_ENDPOINT=minio:9000
|
||||||
|
MINIO_ACCESS_KEY=minioadmin
|
||||||
|
MINIO_SECRET_KEY=minioadmin
|
||||||
|
MINIO_USE_SSL=false
|
||||||
|
MINIO_BUCKET_PREFIX=banatie
|
||||||
|
|
||||||
|
# AI Service Configuration
|
||||||
|
GEMINI_API_KEY=your_gemini_api_key_here
|
||||||
|
|
||||||
|
# Multi-tenancy Configuration
|
||||||
|
DEFAULT_ORG_ID=demo
|
||||||
|
DEFAULT_USER_ID=guest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production Environment (.env.production)
|
||||||
|
|
||||||
|
```env
|
||||||
|
# Application Configuration
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=3000
|
||||||
|
LOG_LEVEL=info
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
DB_HOST=banatie-postgres
|
||||||
|
DB_PORT=5432
|
||||||
|
DB_NAME=banatie_db
|
||||||
|
DB_USER=banatie_user
|
||||||
|
DB_PASSWORD=${SECURE_DB_PASSWORD}
|
||||||
|
|
||||||
|
# MinIO Configuration
|
||||||
|
STORAGE_TYPE=minio
|
||||||
|
MINIO_ENDPOINT=banatie-minio:9000
|
||||||
|
MINIO_ACCESS_KEY=${SECURE_MINIO_ACCESS_KEY}
|
||||||
|
MINIO_SECRET_KEY=${SECURE_MINIO_SECRET_KEY}
|
||||||
|
MINIO_USE_SSL=false
|
||||||
|
MINIO_BUCKET_PREFIX=banatie
|
||||||
|
|
||||||
|
# AI Service Configuration
|
||||||
|
GEMINI_API_KEY=${SECURE_GEMINI_API_KEY}
|
||||||
|
|
||||||
|
# Multi-tenancy Configuration
|
||||||
|
DEFAULT_ORG_ID=demo
|
||||||
|
DEFAULT_USER_ID=guest
|
||||||
|
|
||||||
|
# Security
|
||||||
|
JWT_SECRET=${SECURE_JWT_SECRET}
|
||||||
|
SESSION_SECRET=${SECURE_SESSION_SECRET}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Docker Compose Configurations
|
||||||
|
|
||||||
|
### Development Configuration
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# docker-compose.yml (Local Development)
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
target: development
|
||||||
|
container_name: banatie-app-dev
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
volumes:
|
||||||
|
- ./src:/app/src # Hot reload
|
||||||
|
- ./logs:/app/logs
|
||||||
|
networks:
|
||||||
|
- banatie-dev
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
- minio
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=development
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
container_name: banatie-postgres-dev
|
||||||
|
ports:
|
||||||
|
- "5433:5432" # Avoid conflicts with system PostgreSQL
|
||||||
|
volumes:
|
||||||
|
- ./data/postgres:/var/lib/postgresql/data
|
||||||
|
- ./scripts/init-db.sql:/docker-entrypoint-initdb.d/01-init.sql
|
||||||
|
networks:
|
||||||
|
- banatie-dev
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: banatie_db
|
||||||
|
POSTGRES_USER: banatie_user
|
||||||
|
POSTGRES_PASSWORD: development_password
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U banatie_user -d banatie_db"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
minio:
|
||||||
|
image: minio/minio:latest
|
||||||
|
container_name: banatie-minio-dev
|
||||||
|
ports:
|
||||||
|
- "9000:9000" # S3 API
|
||||||
|
- "9001:9001" # Web Console
|
||||||
|
volumes:
|
||||||
|
- ./data/minio:/data
|
||||||
|
networks:
|
||||||
|
- banatie-dev
|
||||||
|
environment:
|
||||||
|
MINIO_ROOT_USER: minioadmin
|
||||||
|
MINIO_ROOT_PASSWORD: minioadmin
|
||||||
|
command: server /data --console-address ":9001"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
networks:
|
||||||
|
banatie-dev:
|
||||||
|
driver: bridge
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production Configuration
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# docker-compose.yml (Production on VPS)
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
banatie-app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
target: production
|
||||||
|
container_name: banatie-app
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- banatie-network
|
||||||
|
- proxy-network
|
||||||
|
depends_on:
|
||||||
|
banatie-postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
banatie-minio:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
volumes:
|
||||||
|
- ./logs:/app/logs
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 60s
|
||||||
|
|
||||||
|
banatie-postgres:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
container_name: banatie-postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- banatie-network
|
||||||
|
volumes:
|
||||||
|
- ./data/postgres:/var/lib/postgresql/data
|
||||||
|
- ./scripts/init-db.sql:/docker-entrypoint-initdb.d/01-init.sql
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: banatie_db
|
||||||
|
POSTGRES_USER: banatie_user
|
||||||
|
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U banatie_user -d banatie_db"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
banatie-minio:
|
||||||
|
image: minio/minio:latest
|
||||||
|
container_name: banatie-minio
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- banatie-network
|
||||||
|
- proxy-network
|
||||||
|
volumes:
|
||||||
|
- ./data/minio:/data
|
||||||
|
environment:
|
||||||
|
MINIO_ROOT_USER: ${MINIO_ACCESS_KEY}
|
||||||
|
MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY}
|
||||||
|
command: server /data --console-address ":9001"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
networks:
|
||||||
|
banatie-network:
|
||||||
|
driver: bridge
|
||||||
|
internal: true # No external internet access
|
||||||
|
|
||||||
|
proxy-network:
|
||||||
|
external: true # Existing Caddy network
|
||||||
|
```
|
||||||
|
|
||||||
|
## Caddy Integration
|
||||||
|
|
||||||
|
### Caddy Configuration Addition
|
||||||
|
|
||||||
|
Add to existing Caddyfile in `/opt/services/configs/caddy/Caddyfile`:
|
||||||
|
|
||||||
|
```caddy
|
||||||
|
# Banatie App - Main API
|
||||||
|
banatie.app {
|
||||||
|
reverse_proxy banatie-app:3000
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
header {
|
||||||
|
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||||||
|
X-Content-Type-Options "nosniff"
|
||||||
|
X-Frame-Options "DENY"
|
||||||
|
X-XSS-Protection "1; mode=block"
|
||||||
|
Referrer-Policy "strict-origin-when-cross-origin"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Rate limiting
|
||||||
|
rate_limit {
|
||||||
|
zone banatie_api {
|
||||||
|
key {remote_host}
|
||||||
|
events 100
|
||||||
|
window 1m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
log {
|
||||||
|
output file /opt/services/logs/banatie_access.log
|
||||||
|
format json
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# MinIO Console - Admin Interface
|
||||||
|
minio.banatie.app {
|
||||||
|
reverse_proxy banatie-minio:9001
|
||||||
|
|
||||||
|
# Security headers for console
|
||||||
|
header {
|
||||||
|
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||||||
|
X-Content-Type-Options "nosniff"
|
||||||
|
X-Frame-Options "SAMEORIGIN"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
log {
|
||||||
|
output file /opt/services/logs/minio_console_access.log
|
||||||
|
format json
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# MinIO S3 API - Direct file access
|
||||||
|
s3.banatie.app {
|
||||||
|
reverse_proxy banatie-minio:9000
|
||||||
|
|
||||||
|
# CORS for browser uploads
|
||||||
|
header {
|
||||||
|
Access-Control-Allow-Origin "*"
|
||||||
|
Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
||||||
|
Access-Control-Allow-Headers "Content-Type, Authorization"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Rate limiting for uploads
|
||||||
|
rate_limit {
|
||||||
|
zone banatie_s3 {
|
||||||
|
key {remote_host}
|
||||||
|
events 50
|
||||||
|
window 1m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
log {
|
||||||
|
output file /opt/services/logs/minio_s3_access.log
|
||||||
|
format json
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Service Implementation Strategy
|
||||||
|
|
||||||
|
### 1. Storage Service Abstraction
|
||||||
|
|
||||||
|
Create `src/services/StorageService.ts`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export interface StorageService {
|
||||||
|
// Bucket management
|
||||||
|
createBucket(orgId: string): Promise<void>;
|
||||||
|
deleteBucket(orgId: string): Promise<void>;
|
||||||
|
listBuckets(): Promise<string[]>;
|
||||||
|
|
||||||
|
// File operations
|
||||||
|
uploadFile(orgId: string, userId: string, fileName: string, buffer: Buffer, contentType: string): Promise<string>;
|
||||||
|
downloadFile(orgId: string, userId: string, fileName: string): Promise<Buffer>;
|
||||||
|
deleteFile(orgId: string, userId: string, fileName: string): Promise<void>;
|
||||||
|
|
||||||
|
// URL generation
|
||||||
|
getPresignedUploadUrl(orgId: string, userId: string, fileName: string, expirySeconds: number): Promise<string>;
|
||||||
|
getPresignedDownloadUrl(orgId: string, userId: string, fileName: string, expirySeconds: number): Promise<string>;
|
||||||
|
|
||||||
|
// File management
|
||||||
|
listUserFiles(orgId: string, userId: string): Promise<FileMetadata[]>;
|
||||||
|
moveFile(fromPath: string, toPath: string): Promise<void>;
|
||||||
|
copyFile(fromPath: string, toPath: string): Promise<void>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. MinIO Implementation
|
||||||
|
|
||||||
|
Create `src/services/MinioStorageService.ts`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Client as MinioClient } from 'minio';
|
||||||
|
import { StorageService } from './StorageService';
|
||||||
|
|
||||||
|
export class MinioStorageService implements StorageService {
|
||||||
|
private client: MinioClient;
|
||||||
|
private bucketPrefix: string;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
endpoint: string,
|
||||||
|
accessKey: string,
|
||||||
|
secretKey: string,
|
||||||
|
useSSL: boolean = false,
|
||||||
|
bucketPrefix: string = 'banatie'
|
||||||
|
) {
|
||||||
|
this.client = new MinioClient({
|
||||||
|
endPoint: endpoint.replace(/^https?:\/\//, ''),
|
||||||
|
port: useSSL ? 443 : 9000,
|
||||||
|
useSSL,
|
||||||
|
accessKey,
|
||||||
|
secretKey
|
||||||
|
});
|
||||||
|
this.bucketPrefix = bucketPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getBucketName(orgId: string): string {
|
||||||
|
return `${this.bucketPrefix}-${orgId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getFilePath(userId: string, category: 'generated' | 'references' | 'temp', fileName: string): string {
|
||||||
|
const now = new Date();
|
||||||
|
const year = now.getFullYear();
|
||||||
|
const month = String(now.getMonth() + 1).padStart(2, '0');
|
||||||
|
|
||||||
|
return `users/${userId}/${category}/${year}/${month}/${fileName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementation methods...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Database Schema
|
||||||
|
|
||||||
|
Create `scripts/init-db.sql`:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Banatie Database Initialization
|
||||||
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||||
|
|
||||||
|
-- Organizations table
|
||||||
|
CREATE TABLE organizations (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
slug VARCHAR(100) UNIQUE NOT NULL,
|
||||||
|
settings JSONB DEFAULT '{}',
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Users table
|
||||||
|
CREATE TABLE users (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
|
||||||
|
username VARCHAR(100) NOT NULL,
|
||||||
|
email VARCHAR(255),
|
||||||
|
role VARCHAR(50) DEFAULT 'user',
|
||||||
|
settings JSONB DEFAULT '{}',
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
UNIQUE(organization_id, username)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Images table
|
||||||
|
CREATE TABLE images (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
filename VARCHAR(255) NOT NULL,
|
||||||
|
file_path VARCHAR(500) NOT NULL,
|
||||||
|
original_prompt TEXT,
|
||||||
|
enhanced_prompt TEXT,
|
||||||
|
model_used VARCHAR(100),
|
||||||
|
file_size BIGINT,
|
||||||
|
content_type VARCHAR(100),
|
||||||
|
metadata JSONB DEFAULT '{}',
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Upload sessions table (for tracking multi-part uploads)
|
||||||
|
CREATE TABLE upload_sessions (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
session_data JSONB NOT NULL,
|
||||||
|
expires_at TIMESTAMP WITH TIME ZONE,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create indexes
|
||||||
|
CREATE INDEX idx_users_org_id ON users(organization_id);
|
||||||
|
CREATE INDEX idx_images_user_id ON images(user_id);
|
||||||
|
CREATE INDEX idx_images_created_at ON images(created_at);
|
||||||
|
CREATE INDEX idx_upload_sessions_user_id ON upload_sessions(user_id);
|
||||||
|
CREATE INDEX idx_upload_sessions_expires_at ON upload_sessions(expires_at);
|
||||||
|
|
||||||
|
-- Insert demo organization and user
|
||||||
|
INSERT INTO organizations (id, name, slug) VALUES
|
||||||
|
('00000000-0000-0000-0000-000000000001', 'Demo Organization', 'demo');
|
||||||
|
|
||||||
|
INSERT INTO users (id, organization_id, username, role) VALUES
|
||||||
|
('00000000-0000-0000-0000-000000000001', '00000000-0000-0000-0000-000000000001', 'guest', 'user');
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development Workflow
|
||||||
|
|
||||||
|
### Local Development Setup
|
||||||
|
|
||||||
|
1. **Clone Repository**
|
||||||
|
```bash
|
||||||
|
git clone <repository-url>
|
||||||
|
cd banatie-service
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Environment Configuration**
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
# Edit .env with development settings
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Start Development Environment**
|
||||||
|
```bash
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Verify Services**
|
||||||
|
```bash
|
||||||
|
# Check service status
|
||||||
|
docker-compose ps
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
docker-compose logs -f app
|
||||||
|
|
||||||
|
# Access services
|
||||||
|
# App: http://localhost:3000
|
||||||
|
# MinIO Console: http://localhost:9001 (minioadmin/minioadmin)
|
||||||
|
# PostgreSQL: localhost:5433
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Development with Hot Reload**
|
||||||
|
```bash
|
||||||
|
# Edit source files in src/
|
||||||
|
# Changes automatically reload in container
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing Workflow
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run tests in development environment
|
||||||
|
docker-compose exec app pnpm test
|
||||||
|
|
||||||
|
# Run with coverage
|
||||||
|
docker-compose exec app pnpm test:coverage
|
||||||
|
|
||||||
|
# Run linting
|
||||||
|
docker-compose exec app pnpm lint
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production Deployment
|
||||||
|
|
||||||
|
### VPS Deployment Process
|
||||||
|
|
||||||
|
1. **Prepare VPS Directory**
|
||||||
|
```bash
|
||||||
|
# SSH to VPS
|
||||||
|
ssh usul-vps
|
||||||
|
|
||||||
|
# Create Banatie directory
|
||||||
|
sudo mkdir -p /opt/banatie
|
||||||
|
sudo chown usul:usul /opt/banatie
|
||||||
|
cd /opt/banatie
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Clone and Configure**
|
||||||
|
```bash
|
||||||
|
# Clone repository
|
||||||
|
git clone <repository-url> .
|
||||||
|
|
||||||
|
# Create production environment
|
||||||
|
cp .env.example .env
|
||||||
|
# Edit .env with production settings and secure passwords
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Generate Secure Credentials**
|
||||||
|
```bash
|
||||||
|
# Generate secure passwords
|
||||||
|
DB_PASSWORD=$(openssl rand -base64 32 | tr -d '\n\r ')
|
||||||
|
MINIO_ACCESS_KEY=$(openssl rand -base64 20 | tr -d '\n\r ')
|
||||||
|
MINIO_SECRET_KEY=$(openssl rand -base64 40 | tr -d '\n\r ')
|
||||||
|
JWT_SECRET=$(openssl rand -base64 64 | tr -d '\n\r ')
|
||||||
|
|
||||||
|
# Add to .env file
|
||||||
|
echo "DB_PASSWORD=$DB_PASSWORD" >> .env
|
||||||
|
echo "MINIO_ACCESS_KEY=$MINIO_ACCESS_KEY" >> .env
|
||||||
|
echo "MINIO_SECRET_KEY=$MINIO_SECRET_KEY" >> .env
|
||||||
|
echo "JWT_SECRET=$JWT_SECRET" >> .env
|
||||||
|
|
||||||
|
# Secure the file
|
||||||
|
chmod 600 .env
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Update Caddy Configuration**
|
||||||
|
```bash
|
||||||
|
# Add Banatie routes to Caddyfile
|
||||||
|
sudo nano /opt/services/configs/caddy/Caddyfile
|
||||||
|
# Add the Banatie configuration from above
|
||||||
|
|
||||||
|
# Reload Caddy
|
||||||
|
cd /opt/services
|
||||||
|
./manage-services.sh caddy reload
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Deploy Services**
|
||||||
|
```bash
|
||||||
|
cd /opt/banatie
|
||||||
|
|
||||||
|
# Build and start services
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# Verify deployment
|
||||||
|
docker-compose ps
|
||||||
|
docker-compose logs -f
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **Verify Deployment**
|
||||||
|
```bash
|
||||||
|
# Check health endpoints
|
||||||
|
curl https://banatie.app/health
|
||||||
|
curl https://minio.banatie.app/minio/health/live
|
||||||
|
|
||||||
|
# Check logs
|
||||||
|
docker-compose logs banatie-app
|
||||||
|
docker-compose logs banatie-postgres
|
||||||
|
docker-compose logs banatie-minio
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual Update Process
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SSH to VPS
|
||||||
|
ssh usul-vps
|
||||||
|
cd /opt/banatie
|
||||||
|
|
||||||
|
# Pull latest changes
|
||||||
|
git pull origin main
|
||||||
|
|
||||||
|
# Rebuild and restart
|
||||||
|
docker-compose build banatie-app
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# Verify update
|
||||||
|
docker-compose logs -f banatie-app
|
||||||
|
curl https://banatie.app/health
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monitoring and Maintenance
|
||||||
|
|
||||||
|
### Health Checks
|
||||||
|
|
||||||
|
**Application Health Check** (`/health`):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "healthy",
|
||||||
|
"timestamp": "2024-01-01T12:00:00.000Z",
|
||||||
|
"services": {
|
||||||
|
"database": "connected",
|
||||||
|
"minio": "connected",
|
||||||
|
"gemini_api": "accessible"
|
||||||
|
},
|
||||||
|
"version": "1.0.0"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**MinIO Health Check** (`/minio/health/live`):
|
||||||
|
- Returns 200 OK when MinIO is operational
|
||||||
|
- Used by Docker healthcheck and monitoring
|
||||||
|
|
||||||
|
### Log Management
|
||||||
|
|
||||||
|
**Application Logs**:
|
||||||
|
- Location: `/opt/banatie/logs/`
|
||||||
|
- Format: Structured JSON
|
||||||
|
- Rotation: Daily with 30-day retention
|
||||||
|
|
||||||
|
**Access Logs**:
|
||||||
|
- Caddy logs: `/opt/services/logs/banatie_*.log`
|
||||||
|
- Format: JSON with request/response details
|
||||||
|
|
||||||
|
### Backup Strategy
|
||||||
|
|
||||||
|
**Database Backup**:
|
||||||
|
```bash
|
||||||
|
# Create backup
|
||||||
|
docker exec banatie-postgres pg_dump -U banatie_user banatie_db > banatie_db_backup.sql
|
||||||
|
|
||||||
|
# Restore backup
|
||||||
|
docker exec -i banatie-postgres psql -U banatie_user banatie_db < banatie_db_backup.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
**MinIO Data Backup**:
|
||||||
|
```bash
|
||||||
|
# Backup MinIO data
|
||||||
|
sudo tar -czf banatie_minio_backup.tar.gz -C /opt/banatie/data minio/
|
||||||
|
|
||||||
|
# Restore MinIO data
|
||||||
|
sudo tar -xzf banatie_minio_backup.tar.gz -C /opt/banatie/data
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
### Container Security
|
||||||
|
- Non-root users in containers
|
||||||
|
- Read-only root filesystems where possible
|
||||||
|
- Resource limits (memory, CPU)
|
||||||
|
- Health checks for automatic restart
|
||||||
|
|
||||||
|
### Network Security
|
||||||
|
- Internal network isolation
|
||||||
|
- No direct external access to database or MinIO
|
||||||
|
- Rate limiting at proxy level
|
||||||
|
- HTTPS-only external access
|
||||||
|
|
||||||
|
### Data Security
|
||||||
|
- Encrypted environment variables
|
||||||
|
- Secure secret generation
|
||||||
|
- Regular credential rotation
|
||||||
|
- Audit logging
|
||||||
|
|
||||||
|
### Access Control
|
||||||
|
- MinIO bucket policies per organization
|
||||||
|
- PostgreSQL row-level security
|
||||||
|
- JWT-based API authentication
|
||||||
|
- Role-based access control
|
||||||
|
|
||||||
|
## Future Scalability
|
||||||
|
|
||||||
|
### Horizontal Scaling Options
|
||||||
|
- Multiple Banatie app containers behind load balancer
|
||||||
|
- MinIO distributed mode for storage scaling
|
||||||
|
- PostgreSQL read replicas for read scaling
|
||||||
|
- Redis for session storage and caching
|
||||||
|
|
||||||
|
### Multi-Region Deployment
|
||||||
|
- Regional MinIO clusters
|
||||||
|
- Database replication
|
||||||
|
- CDN integration for static assets
|
||||||
|
- Geo-distributed deployment
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
**Container Won't Start**:
|
||||||
|
```bash
|
||||||
|
# Check logs
|
||||||
|
docker-compose logs [service-name]
|
||||||
|
|
||||||
|
# Check resource usage
|
||||||
|
docker stats
|
||||||
|
|
||||||
|
# Rebuild container
|
||||||
|
docker-compose build [service-name]
|
||||||
|
docker-compose up -d [service-name]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Database Connection Issues**:
|
||||||
|
```bash
|
||||||
|
# Test database connectivity
|
||||||
|
docker exec banatie-postgres pg_isready -U banatie_user -d banatie_db
|
||||||
|
|
||||||
|
# Check environment variables
|
||||||
|
docker exec banatie-app env | grep DB_
|
||||||
|
|
||||||
|
# Restart database
|
||||||
|
docker-compose restart banatie-postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
**MinIO Access Issues**:
|
||||||
|
```bash
|
||||||
|
# Check MinIO status
|
||||||
|
docker exec banatie-minio mc admin info local
|
||||||
|
|
||||||
|
# Test S3 API
|
||||||
|
curl -f http://localhost:9000/minio/health/live
|
||||||
|
|
||||||
|
# Check access keys
|
||||||
|
docker exec banatie-app env | grep MINIO_
|
||||||
|
```
|
||||||
|
|
||||||
|
**Network Connectivity**:
|
||||||
|
```bash
|
||||||
|
# Check networks
|
||||||
|
docker network ls
|
||||||
|
docker network inspect banatie_banatie-network
|
||||||
|
|
||||||
|
# Test internal connectivity
|
||||||
|
docker exec banatie-app ping banatie-postgres
|
||||||
|
docker exec banatie-app ping banatie-minio
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Document Version**: 1.0
|
||||||
|
**Last Updated**: 2024-09-26
|
||||||
|
**Maintained By**: Banatie Development Team
|
||||||
|
|
@ -43,7 +43,8 @@
|
||||||
"express-rate-limit": "^7.4.1",
|
"express-rate-limit": "^7.4.1",
|
||||||
"express-validator": "^7.2.0",
|
"express-validator": "^7.2.0",
|
||||||
"helmet": "^8.0.0",
|
"helmet": "^8.0.0",
|
||||||
"mime": "^4.1.0",
|
"mime": "3.0.0",
|
||||||
|
"minio": "^8.0.6",
|
||||||
"multer": "^2.0.2",
|
"multer": "^2.0.2",
|
||||||
"winston": "^3.17.0"
|
"winston": "^3.17.0"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
310
pnpm-lock.yaml
310
pnpm-lock.yaml
|
|
@ -30,8 +30,11 @@ importers:
|
||||||
specifier: ^8.0.0
|
specifier: ^8.0.0
|
||||||
version: 8.1.0
|
version: 8.1.0
|
||||||
mime:
|
mime:
|
||||||
specifier: ^4.1.0
|
specifier: 3.0.0
|
||||||
version: 4.1.0
|
version: 3.0.0
|
||||||
|
minio:
|
||||||
|
specifier: ^8.0.6
|
||||||
|
version: 8.0.6
|
||||||
multer:
|
multer:
|
||||||
specifier: ^2.0.2
|
specifier: ^2.0.2
|
||||||
version: 2.0.2
|
version: 2.0.2
|
||||||
|
|
@ -767,6 +770,9 @@ packages:
|
||||||
resolution: {integrity: sha512-zaz9u8EJ4GBmnehlrpoKvj/E3dNbuQ7q0ucyZImm3cLqJ8INTc970B1qEqDX/Rzq65r3TvVTN7kHWPBoyW7DWw==}
|
resolution: {integrity: sha512-zaz9u8EJ4GBmnehlrpoKvj/E3dNbuQ7q0ucyZImm3cLqJ8INTc970B1qEqDX/Rzq65r3TvVTN7kHWPBoyW7DWw==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
|
'@zxing/text-encoding@0.9.0':
|
||||||
|
resolution: {integrity: sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==}
|
||||||
|
|
||||||
accepts@2.0.0:
|
accepts@2.0.0:
|
||||||
resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
|
resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
@ -826,6 +832,10 @@ packages:
|
||||||
asynckit@0.4.0:
|
asynckit@0.4.0:
|
||||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||||
|
|
||||||
|
available-typed-arrays@1.0.7:
|
||||||
|
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
babel-jest@29.7.0:
|
babel-jest@29.7.0:
|
||||||
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
|
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||||
|
|
@ -868,6 +878,9 @@ packages:
|
||||||
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
block-stream2@2.1.0:
|
||||||
|
resolution: {integrity: sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg==}
|
||||||
|
|
||||||
body-parser@2.2.0:
|
body-parser@2.2.0:
|
||||||
resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==}
|
resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
@ -882,6 +895,9 @@ packages:
|
||||||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
browser-or-node@2.1.1:
|
||||||
|
resolution: {integrity: sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==}
|
||||||
|
|
||||||
browserslist@4.26.2:
|
browserslist@4.26.2:
|
||||||
resolution: {integrity: sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==}
|
resolution: {integrity: sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==}
|
||||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||||
|
|
@ -894,6 +910,10 @@ packages:
|
||||||
bser@2.1.1:
|
bser@2.1.1:
|
||||||
resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
|
resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
|
||||||
|
|
||||||
|
buffer-crc32@1.0.0:
|
||||||
|
resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==}
|
||||||
|
engines: {node: '>=8.0.0'}
|
||||||
|
|
||||||
buffer-equal-constant-time@1.0.1:
|
buffer-equal-constant-time@1.0.1:
|
||||||
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
|
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
|
||||||
|
|
||||||
|
|
@ -912,6 +932,10 @@ packages:
|
||||||
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
call-bind@1.0.8:
|
||||||
|
resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
call-bound@1.0.4:
|
call-bound@1.0.4:
|
||||||
resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
|
resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
@ -1041,6 +1065,10 @@ packages:
|
||||||
supports-color:
|
supports-color:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
decode-uri-component@0.2.2:
|
||||||
|
resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==}
|
||||||
|
engines: {node: '>=0.10'}
|
||||||
|
|
||||||
dedent@1.7.0:
|
dedent@1.7.0:
|
||||||
resolution: {integrity: sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==}
|
resolution: {integrity: sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
@ -1056,6 +1084,10 @@ packages:
|
||||||
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
define-data-property@1.1.4:
|
||||||
|
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
delayed-stream@1.0.0:
|
delayed-stream@1.0.0:
|
||||||
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
|
|
@ -1216,6 +1248,9 @@ packages:
|
||||||
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
|
eventemitter3@5.0.1:
|
||||||
|
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
|
||||||
|
|
||||||
execa@5.1.1:
|
execa@5.1.1:
|
||||||
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
|
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
@ -1264,6 +1299,10 @@ packages:
|
||||||
fast-safe-stringify@2.1.1:
|
fast-safe-stringify@2.1.1:
|
||||||
resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
|
resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
|
||||||
|
|
||||||
|
fast-xml-parser@4.5.3:
|
||||||
|
resolution: {integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
fastq@1.19.1:
|
fastq@1.19.1:
|
||||||
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
|
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
|
||||||
|
|
||||||
|
|
@ -1281,6 +1320,10 @@ packages:
|
||||||
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
filter-obj@1.1.0:
|
||||||
|
resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
finalhandler@2.1.0:
|
finalhandler@2.1.0:
|
||||||
resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==}
|
resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
@ -1303,6 +1346,10 @@ packages:
|
||||||
fn.name@1.1.0:
|
fn.name@1.1.0:
|
||||||
resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==}
|
resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==}
|
||||||
|
|
||||||
|
for-each@0.3.5:
|
||||||
|
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
form-data@4.0.4:
|
form-data@4.0.4:
|
||||||
resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==}
|
resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
|
@ -1416,6 +1463,9 @@ packages:
|
||||||
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
has-property-descriptors@1.0.2:
|
||||||
|
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
|
||||||
|
|
||||||
has-symbols@1.1.0:
|
has-symbols@1.1.0:
|
||||||
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
|
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
@ -1490,6 +1540,14 @@ packages:
|
||||||
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
|
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
|
||||||
engines: {node: '>= 0.10'}
|
engines: {node: '>= 0.10'}
|
||||||
|
|
||||||
|
ipaddr.js@2.2.0:
|
||||||
|
resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
|
||||||
|
is-arguments@1.2.0:
|
||||||
|
resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
is-arrayish@0.2.1:
|
is-arrayish@0.2.1:
|
||||||
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
|
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
|
||||||
|
|
||||||
|
|
@ -1500,6 +1558,10 @@ packages:
|
||||||
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
|
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
is-callable@1.2.7:
|
||||||
|
resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
is-core-module@2.16.1:
|
is-core-module@2.16.1:
|
||||||
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
|
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
@ -1516,6 +1578,10 @@ packages:
|
||||||
resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
|
resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
is-generator-function@1.1.0:
|
||||||
|
resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
is-glob@4.0.3:
|
is-glob@4.0.3:
|
||||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
@ -1527,10 +1593,18 @@ packages:
|
||||||
is-promise@4.0.0:
|
is-promise@4.0.0:
|
||||||
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
|
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
|
||||||
|
|
||||||
|
is-regex@1.2.1:
|
||||||
|
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
is-stream@2.0.1:
|
is-stream@2.0.1:
|
||||||
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
|
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
is-typed-array@1.1.15:
|
||||||
|
resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
isexe@2.0.0:
|
isexe@2.0.0:
|
||||||
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||||
|
|
||||||
|
|
@ -1836,9 +1910,9 @@ packages:
|
||||||
engines: {node: '>=4.0.0'}
|
engines: {node: '>=4.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
mime@4.1.0:
|
mime@3.0.0:
|
||||||
resolution: {integrity: sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==}
|
resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=10.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
mimic-fn@2.1.0:
|
mimic-fn@2.1.0:
|
||||||
|
|
@ -1855,6 +1929,10 @@ packages:
|
||||||
minimist@1.2.8:
|
minimist@1.2.8:
|
||||||
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
|
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
|
||||||
|
|
||||||
|
minio@8.0.6:
|
||||||
|
resolution: {integrity: sha512-sOeh2/b/XprRmEtYsnNRFtOqNRTPDvYtMWh+spWlfsuCV/+IdxNeKVUMKLqI7b5Dr07ZqCPuaRGU/rB9pZYVdQ==}
|
||||||
|
engines: {node: ^16 || ^18 || >=20}
|
||||||
|
|
||||||
mkdirp@0.5.6:
|
mkdirp@0.5.6:
|
||||||
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
|
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
@ -1995,6 +2073,10 @@ packages:
|
||||||
resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
|
resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
possible-typed-array-names@1.1.0:
|
||||||
|
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
prelude-ls@1.2.1:
|
prelude-ls@1.2.1:
|
||||||
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
@ -2034,6 +2116,10 @@ packages:
|
||||||
resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
|
resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
|
||||||
engines: {node: '>=0.6'}
|
engines: {node: '>=0.6'}
|
||||||
|
|
||||||
|
query-string@7.1.3:
|
||||||
|
resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
queue-microtask@1.2.3:
|
queue-microtask@1.2.3:
|
||||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||||
|
|
||||||
|
|
@ -2098,6 +2184,10 @@ packages:
|
||||||
safe-buffer@5.2.1:
|
safe-buffer@5.2.1:
|
||||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||||
|
|
||||||
|
safe-regex-test@1.1.0:
|
||||||
|
resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
safe-stable-stringify@2.5.0:
|
safe-stable-stringify@2.5.0:
|
||||||
resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==}
|
resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
@ -2105,6 +2195,9 @@ packages:
|
||||||
safer-buffer@2.1.2:
|
safer-buffer@2.1.2:
|
||||||
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
||||||
|
|
||||||
|
sax@1.4.1:
|
||||||
|
resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
|
||||||
|
|
||||||
semver@6.3.1:
|
semver@6.3.1:
|
||||||
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
|
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
@ -2122,6 +2215,10 @@ packages:
|
||||||
resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==}
|
resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==}
|
||||||
engines: {node: '>= 18'}
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
set-function-length@1.2.2:
|
||||||
|
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
setprototypeof@1.2.0:
|
setprototypeof@1.2.0:
|
||||||
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||||
|
|
||||||
|
|
@ -2173,6 +2270,10 @@ packages:
|
||||||
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
|
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
split-on-first@1.1.0:
|
||||||
|
resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
sprintf-js@1.0.3:
|
sprintf-js@1.0.3:
|
||||||
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
|
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
|
||||||
|
|
||||||
|
|
@ -2191,10 +2292,20 @@ packages:
|
||||||
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
|
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
|
stream-chain@2.2.5:
|
||||||
|
resolution: {integrity: sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==}
|
||||||
|
|
||||||
|
stream-json@1.9.1:
|
||||||
|
resolution: {integrity: sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==}
|
||||||
|
|
||||||
streamsearch@1.1.0:
|
streamsearch@1.1.0:
|
||||||
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
|
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
|
strict-uri-encode@2.0.0:
|
||||||
|
resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
string-length@4.0.2:
|
string-length@4.0.2:
|
||||||
resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
|
resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
@ -2222,6 +2333,9 @@ packages:
|
||||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
strnum@1.1.2:
|
||||||
|
resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==}
|
||||||
|
|
||||||
superagent@10.2.3:
|
superagent@10.2.3:
|
||||||
resolution: {integrity: sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==}
|
resolution: {integrity: sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==}
|
||||||
engines: {node: '>=14.18.0'}
|
engines: {node: '>=14.18.0'}
|
||||||
|
|
@ -2257,6 +2371,9 @@ packages:
|
||||||
text-hex@1.0.0:
|
text-hex@1.0.0:
|
||||||
resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==}
|
resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==}
|
||||||
|
|
||||||
|
through2@4.0.2:
|
||||||
|
resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==}
|
||||||
|
|
||||||
tmpl@1.0.5:
|
tmpl@1.0.5:
|
||||||
resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
|
resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
|
||||||
|
|
||||||
|
|
@ -2376,6 +2493,9 @@ packages:
|
||||||
util-deprecate@1.0.2:
|
util-deprecate@1.0.2:
|
||||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||||
|
|
||||||
|
util@0.12.5:
|
||||||
|
resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==}
|
||||||
|
|
||||||
uuid@9.0.1:
|
uuid@9.0.1:
|
||||||
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
|
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
@ -2395,12 +2515,19 @@ packages:
|
||||||
walker@1.0.8:
|
walker@1.0.8:
|
||||||
resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
|
resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
|
||||||
|
|
||||||
|
web-encoding@1.1.5:
|
||||||
|
resolution: {integrity: sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==}
|
||||||
|
|
||||||
webidl-conversions@3.0.1:
|
webidl-conversions@3.0.1:
|
||||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||||
|
|
||||||
whatwg-url@5.0.0:
|
whatwg-url@5.0.0:
|
||||||
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
||||||
|
|
||||||
|
which-typed-array@1.1.19:
|
||||||
|
resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
which@2.0.2:
|
which@2.0.2:
|
||||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
@ -2444,6 +2571,14 @@ packages:
|
||||||
utf-8-validate:
|
utf-8-validate:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
xml2js@0.6.2:
|
||||||
|
resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==}
|
||||||
|
engines: {node: '>=4.0.0'}
|
||||||
|
|
||||||
|
xmlbuilder@11.0.1:
|
||||||
|
resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==}
|
||||||
|
engines: {node: '>=4.0'}
|
||||||
|
|
||||||
xtend@4.0.2:
|
xtend@4.0.2:
|
||||||
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
|
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
|
||||||
engines: {node: '>=0.4'}
|
engines: {node: '>=0.4'}
|
||||||
|
|
@ -3246,6 +3381,9 @@ snapshots:
|
||||||
'@typescript-eslint/types': 8.44.0
|
'@typescript-eslint/types': 8.44.0
|
||||||
eslint-visitor-keys: 4.2.1
|
eslint-visitor-keys: 4.2.1
|
||||||
|
|
||||||
|
'@zxing/text-encoding@0.9.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
accepts@2.0.0:
|
accepts@2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
mime-types: 3.0.1
|
mime-types: 3.0.1
|
||||||
|
|
@ -3297,6 +3435,10 @@ snapshots:
|
||||||
|
|
||||||
asynckit@0.4.0: {}
|
asynckit@0.4.0: {}
|
||||||
|
|
||||||
|
available-typed-arrays@1.0.7:
|
||||||
|
dependencies:
|
||||||
|
possible-typed-array-names: 1.1.0
|
||||||
|
|
||||||
babel-jest@29.7.0(@babel/core@7.28.4):
|
babel-jest@29.7.0(@babel/core@7.28.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.28.4
|
'@babel/core': 7.28.4
|
||||||
|
|
@ -3362,6 +3504,10 @@ snapshots:
|
||||||
|
|
||||||
binary-extensions@2.3.0: {}
|
binary-extensions@2.3.0: {}
|
||||||
|
|
||||||
|
block-stream2@2.1.0:
|
||||||
|
dependencies:
|
||||||
|
readable-stream: 3.6.2
|
||||||
|
|
||||||
body-parser@2.2.0:
|
body-parser@2.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
bytes: 3.1.2
|
bytes: 3.1.2
|
||||||
|
|
@ -3389,6 +3535,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
fill-range: 7.1.1
|
fill-range: 7.1.1
|
||||||
|
|
||||||
|
browser-or-node@2.1.1: {}
|
||||||
|
|
||||||
browserslist@4.26.2:
|
browserslist@4.26.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
baseline-browser-mapping: 2.8.6
|
baseline-browser-mapping: 2.8.6
|
||||||
|
|
@ -3405,6 +3553,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
node-int64: 0.4.0
|
node-int64: 0.4.0
|
||||||
|
|
||||||
|
buffer-crc32@1.0.0: {}
|
||||||
|
|
||||||
buffer-equal-constant-time@1.0.1: {}
|
buffer-equal-constant-time@1.0.1: {}
|
||||||
|
|
||||||
buffer-from@1.1.2: {}
|
buffer-from@1.1.2: {}
|
||||||
|
|
@ -3420,6 +3570,13 @@ snapshots:
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
|
|
||||||
|
call-bind@1.0.8:
|
||||||
|
dependencies:
|
||||||
|
call-bind-apply-helpers: 1.0.2
|
||||||
|
es-define-property: 1.0.1
|
||||||
|
get-intrinsic: 1.3.0
|
||||||
|
set-function-length: 1.2.2
|
||||||
|
|
||||||
call-bound@1.0.4:
|
call-bound@1.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind-apply-helpers: 1.0.2
|
call-bind-apply-helpers: 1.0.2
|
||||||
|
|
@ -3554,12 +3711,20 @@ snapshots:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
supports-color: 5.5.0
|
supports-color: 5.5.0
|
||||||
|
|
||||||
|
decode-uri-component@0.2.2: {}
|
||||||
|
|
||||||
dedent@1.7.0: {}
|
dedent@1.7.0: {}
|
||||||
|
|
||||||
deep-is@0.1.4: {}
|
deep-is@0.1.4: {}
|
||||||
|
|
||||||
deepmerge@4.3.1: {}
|
deepmerge@4.3.1: {}
|
||||||
|
|
||||||
|
define-data-property@1.1.4:
|
||||||
|
dependencies:
|
||||||
|
es-define-property: 1.0.1
|
||||||
|
es-errors: 1.3.0
|
||||||
|
gopd: 1.2.0
|
||||||
|
|
||||||
delayed-stream@1.0.0: {}
|
delayed-stream@1.0.0: {}
|
||||||
|
|
||||||
depd@2.0.0: {}
|
depd@2.0.0: {}
|
||||||
|
|
@ -3737,6 +3902,8 @@ snapshots:
|
||||||
|
|
||||||
etag@1.8.1: {}
|
etag@1.8.1: {}
|
||||||
|
|
||||||
|
eventemitter3@5.0.1: {}
|
||||||
|
|
||||||
execa@5.1.1:
|
execa@5.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
cross-spawn: 7.0.6
|
cross-spawn: 7.0.6
|
||||||
|
|
@ -3820,6 +3987,10 @@ snapshots:
|
||||||
|
|
||||||
fast-safe-stringify@2.1.1: {}
|
fast-safe-stringify@2.1.1: {}
|
||||||
|
|
||||||
|
fast-xml-parser@4.5.3:
|
||||||
|
dependencies:
|
||||||
|
strnum: 1.1.2
|
||||||
|
|
||||||
fastq@1.19.1:
|
fastq@1.19.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
reusify: 1.1.0
|
reusify: 1.1.0
|
||||||
|
|
@ -3838,6 +4009,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
to-regex-range: 5.0.1
|
to-regex-range: 5.0.1
|
||||||
|
|
||||||
|
filter-obj@1.1.0: {}
|
||||||
|
|
||||||
finalhandler@2.1.0:
|
finalhandler@2.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.3(supports-color@5.5.0)
|
debug: 4.4.3(supports-color@5.5.0)
|
||||||
|
|
@ -3868,6 +4041,10 @@ snapshots:
|
||||||
|
|
||||||
fn.name@1.1.0: {}
|
fn.name@1.1.0: {}
|
||||||
|
|
||||||
|
for-each@0.3.5:
|
||||||
|
dependencies:
|
||||||
|
is-callable: 1.2.7
|
||||||
|
|
||||||
form-data@4.0.4:
|
form-data@4.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
asynckit: 0.4.0
|
asynckit: 0.4.0
|
||||||
|
|
@ -4003,6 +4180,10 @@ snapshots:
|
||||||
|
|
||||||
has-flag@4.0.0: {}
|
has-flag@4.0.0: {}
|
||||||
|
|
||||||
|
has-property-descriptors@1.0.2:
|
||||||
|
dependencies:
|
||||||
|
es-define-property: 1.0.1
|
||||||
|
|
||||||
has-symbols@1.1.0: {}
|
has-symbols@1.1.0: {}
|
||||||
|
|
||||||
has-tostringtag@1.0.2:
|
has-tostringtag@1.0.2:
|
||||||
|
|
@ -4069,6 +4250,13 @@ snapshots:
|
||||||
|
|
||||||
ipaddr.js@1.9.1: {}
|
ipaddr.js@1.9.1: {}
|
||||||
|
|
||||||
|
ipaddr.js@2.2.0: {}
|
||||||
|
|
||||||
|
is-arguments@1.2.0:
|
||||||
|
dependencies:
|
||||||
|
call-bound: 1.0.4
|
||||||
|
has-tostringtag: 1.0.2
|
||||||
|
|
||||||
is-arrayish@0.2.1: {}
|
is-arrayish@0.2.1: {}
|
||||||
|
|
||||||
is-arrayish@0.3.4: {}
|
is-arrayish@0.3.4: {}
|
||||||
|
|
@ -4077,6 +4265,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
binary-extensions: 2.3.0
|
binary-extensions: 2.3.0
|
||||||
|
|
||||||
|
is-callable@1.2.7: {}
|
||||||
|
|
||||||
is-core-module@2.16.1:
|
is-core-module@2.16.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
hasown: 2.0.2
|
hasown: 2.0.2
|
||||||
|
|
@ -4087,6 +4277,13 @@ snapshots:
|
||||||
|
|
||||||
is-generator-fn@2.1.0: {}
|
is-generator-fn@2.1.0: {}
|
||||||
|
|
||||||
|
is-generator-function@1.1.0:
|
||||||
|
dependencies:
|
||||||
|
call-bound: 1.0.4
|
||||||
|
get-proto: 1.0.1
|
||||||
|
has-tostringtag: 1.0.2
|
||||||
|
safe-regex-test: 1.1.0
|
||||||
|
|
||||||
is-glob@4.0.3:
|
is-glob@4.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-extglob: 2.1.1
|
is-extglob: 2.1.1
|
||||||
|
|
@ -4095,8 +4292,19 @@ snapshots:
|
||||||
|
|
||||||
is-promise@4.0.0: {}
|
is-promise@4.0.0: {}
|
||||||
|
|
||||||
|
is-regex@1.2.1:
|
||||||
|
dependencies:
|
||||||
|
call-bound: 1.0.4
|
||||||
|
gopd: 1.2.0
|
||||||
|
has-tostringtag: 1.0.2
|
||||||
|
hasown: 2.0.2
|
||||||
|
|
||||||
is-stream@2.0.1: {}
|
is-stream@2.0.1: {}
|
||||||
|
|
||||||
|
is-typed-array@1.1.15:
|
||||||
|
dependencies:
|
||||||
|
which-typed-array: 1.1.19
|
||||||
|
|
||||||
isexe@2.0.0: {}
|
isexe@2.0.0: {}
|
||||||
|
|
||||||
istanbul-lib-coverage@3.2.2: {}
|
istanbul-lib-coverage@3.2.2: {}
|
||||||
|
|
@ -4573,7 +4781,7 @@ snapshots:
|
||||||
|
|
||||||
mime@2.6.0: {}
|
mime@2.6.0: {}
|
||||||
|
|
||||||
mime@4.1.0: {}
|
mime@3.0.0: {}
|
||||||
|
|
||||||
mimic-fn@2.1.0: {}
|
mimic-fn@2.1.0: {}
|
||||||
|
|
||||||
|
|
@ -4587,6 +4795,23 @@ snapshots:
|
||||||
|
|
||||||
minimist@1.2.8: {}
|
minimist@1.2.8: {}
|
||||||
|
|
||||||
|
minio@8.0.6:
|
||||||
|
dependencies:
|
||||||
|
async: 3.2.6
|
||||||
|
block-stream2: 2.1.0
|
||||||
|
browser-or-node: 2.1.1
|
||||||
|
buffer-crc32: 1.0.0
|
||||||
|
eventemitter3: 5.0.1
|
||||||
|
fast-xml-parser: 4.5.3
|
||||||
|
ipaddr.js: 2.2.0
|
||||||
|
lodash: 4.17.21
|
||||||
|
mime-types: 2.1.35
|
||||||
|
query-string: 7.1.3
|
||||||
|
stream-json: 1.9.1
|
||||||
|
through2: 4.0.2
|
||||||
|
web-encoding: 1.1.5
|
||||||
|
xml2js: 0.6.2
|
||||||
|
|
||||||
mkdirp@0.5.6:
|
mkdirp@0.5.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
minimist: 1.2.8
|
minimist: 1.2.8
|
||||||
|
|
@ -4716,6 +4941,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
find-up: 4.1.0
|
find-up: 4.1.0
|
||||||
|
|
||||||
|
possible-typed-array-names@1.1.0: {}
|
||||||
|
|
||||||
prelude-ls@1.2.1: {}
|
prelude-ls@1.2.1: {}
|
||||||
|
|
||||||
prettier-linter-helpers@1.0.0:
|
prettier-linter-helpers@1.0.0:
|
||||||
|
|
@ -4750,6 +4977,13 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
side-channel: 1.1.0
|
side-channel: 1.1.0
|
||||||
|
|
||||||
|
query-string@7.1.3:
|
||||||
|
dependencies:
|
||||||
|
decode-uri-component: 0.2.2
|
||||||
|
filter-obj: 1.1.0
|
||||||
|
split-on-first: 1.1.0
|
||||||
|
strict-uri-encode: 2.0.0
|
||||||
|
|
||||||
queue-microtask@1.2.3: {}
|
queue-microtask@1.2.3: {}
|
||||||
|
|
||||||
range-parser@1.2.1: {}
|
range-parser@1.2.1: {}
|
||||||
|
|
@ -4811,10 +5045,18 @@ snapshots:
|
||||||
|
|
||||||
safe-buffer@5.2.1: {}
|
safe-buffer@5.2.1: {}
|
||||||
|
|
||||||
|
safe-regex-test@1.1.0:
|
||||||
|
dependencies:
|
||||||
|
call-bound: 1.0.4
|
||||||
|
es-errors: 1.3.0
|
||||||
|
is-regex: 1.2.1
|
||||||
|
|
||||||
safe-stable-stringify@2.5.0: {}
|
safe-stable-stringify@2.5.0: {}
|
||||||
|
|
||||||
safer-buffer@2.1.2: {}
|
safer-buffer@2.1.2: {}
|
||||||
|
|
||||||
|
sax@1.4.1: {}
|
||||||
|
|
||||||
semver@6.3.1: {}
|
semver@6.3.1: {}
|
||||||
|
|
||||||
semver@7.7.2: {}
|
semver@7.7.2: {}
|
||||||
|
|
@ -4844,6 +5086,15 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
set-function-length@1.2.2:
|
||||||
|
dependencies:
|
||||||
|
define-data-property: 1.1.4
|
||||||
|
es-errors: 1.3.0
|
||||||
|
function-bind: 1.1.2
|
||||||
|
get-intrinsic: 1.3.0
|
||||||
|
gopd: 1.2.0
|
||||||
|
has-property-descriptors: 1.0.2
|
||||||
|
|
||||||
setprototypeof@1.2.0: {}
|
setprototypeof@1.2.0: {}
|
||||||
|
|
||||||
shebang-command@2.0.0:
|
shebang-command@2.0.0:
|
||||||
|
|
@ -4901,6 +5152,8 @@ snapshots:
|
||||||
|
|
||||||
source-map@0.6.1: {}
|
source-map@0.6.1: {}
|
||||||
|
|
||||||
|
split-on-first@1.1.0: {}
|
||||||
|
|
||||||
sprintf-js@1.0.3: {}
|
sprintf-js@1.0.3: {}
|
||||||
|
|
||||||
stack-trace@0.0.10: {}
|
stack-trace@0.0.10: {}
|
||||||
|
|
@ -4913,8 +5166,16 @@ snapshots:
|
||||||
|
|
||||||
statuses@2.0.2: {}
|
statuses@2.0.2: {}
|
||||||
|
|
||||||
|
stream-chain@2.2.5: {}
|
||||||
|
|
||||||
|
stream-json@1.9.1:
|
||||||
|
dependencies:
|
||||||
|
stream-chain: 2.2.5
|
||||||
|
|
||||||
streamsearch@1.1.0: {}
|
streamsearch@1.1.0: {}
|
||||||
|
|
||||||
|
strict-uri-encode@2.0.0: {}
|
||||||
|
|
||||||
string-length@4.0.2:
|
string-length@4.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
char-regex: 1.0.2
|
char-regex: 1.0.2
|
||||||
|
|
@ -4940,6 +5201,8 @@ snapshots:
|
||||||
|
|
||||||
strip-json-comments@3.1.1: {}
|
strip-json-comments@3.1.1: {}
|
||||||
|
|
||||||
|
strnum@1.1.2: {}
|
||||||
|
|
||||||
superagent@10.2.3:
|
superagent@10.2.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
component-emitter: 1.3.1
|
component-emitter: 1.3.1
|
||||||
|
|
@ -4987,6 +5250,10 @@ snapshots:
|
||||||
|
|
||||||
text-hex@1.0.0: {}
|
text-hex@1.0.0: {}
|
||||||
|
|
||||||
|
through2@4.0.2:
|
||||||
|
dependencies:
|
||||||
|
readable-stream: 3.6.2
|
||||||
|
|
||||||
tmpl@1.0.5: {}
|
tmpl@1.0.5: {}
|
||||||
|
|
||||||
to-regex-range@5.0.1:
|
to-regex-range@5.0.1:
|
||||||
|
|
@ -5078,6 +5345,14 @@ snapshots:
|
||||||
|
|
||||||
util-deprecate@1.0.2: {}
|
util-deprecate@1.0.2: {}
|
||||||
|
|
||||||
|
util@0.12.5:
|
||||||
|
dependencies:
|
||||||
|
inherits: 2.0.4
|
||||||
|
is-arguments: 1.2.0
|
||||||
|
is-generator-function: 1.1.0
|
||||||
|
is-typed-array: 1.1.15
|
||||||
|
which-typed-array: 1.1.19
|
||||||
|
|
||||||
uuid@9.0.1: {}
|
uuid@9.0.1: {}
|
||||||
|
|
||||||
v8-to-istanbul@9.3.0:
|
v8-to-istanbul@9.3.0:
|
||||||
|
|
@ -5094,6 +5369,12 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
makeerror: 1.0.12
|
makeerror: 1.0.12
|
||||||
|
|
||||||
|
web-encoding@1.1.5:
|
||||||
|
dependencies:
|
||||||
|
util: 0.12.5
|
||||||
|
optionalDependencies:
|
||||||
|
'@zxing/text-encoding': 0.9.0
|
||||||
|
|
||||||
webidl-conversions@3.0.1: {}
|
webidl-conversions@3.0.1: {}
|
||||||
|
|
||||||
whatwg-url@5.0.0:
|
whatwg-url@5.0.0:
|
||||||
|
|
@ -5101,6 +5382,16 @@ snapshots:
|
||||||
tr46: 0.0.3
|
tr46: 0.0.3
|
||||||
webidl-conversions: 3.0.1
|
webidl-conversions: 3.0.1
|
||||||
|
|
||||||
|
which-typed-array@1.1.19:
|
||||||
|
dependencies:
|
||||||
|
available-typed-arrays: 1.0.7
|
||||||
|
call-bind: 1.0.8
|
||||||
|
call-bound: 1.0.4
|
||||||
|
for-each: 0.3.5
|
||||||
|
get-proto: 1.0.1
|
||||||
|
gopd: 1.2.0
|
||||||
|
has-tostringtag: 1.0.2
|
||||||
|
|
||||||
which@2.0.2:
|
which@2.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
isexe: 2.0.0
|
isexe: 2.0.0
|
||||||
|
|
@ -5144,6 +5435,13 @@ snapshots:
|
||||||
|
|
||||||
ws@8.18.3: {}
|
ws@8.18.3: {}
|
||||||
|
|
||||||
|
xml2js@0.6.2:
|
||||||
|
dependencies:
|
||||||
|
sax: 1.4.1
|
||||||
|
xmlbuilder: 11.0.1
|
||||||
|
|
||||||
|
xmlbuilder@11.0.1: {}
|
||||||
|
|
||||||
xtend@4.0.2: {}
|
xtend@4.0.2: {}
|
||||||
|
|
||||||
y18n@5.0.8: {}
|
y18n@5.0.8: {}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
-- Banatie Database Initialization Script
|
||||||
|
-- This script creates the database schema for the Banatie image generation service
|
||||||
|
|
||||||
|
-- Enable UUID extension for generating UUIDs
|
||||||
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||||
|
|
||||||
|
-- Organizations table - for multi-tenant support
|
||||||
|
CREATE TABLE organizations (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
slug VARCHAR(100) UNIQUE NOT NULL,
|
||||||
|
settings JSONB DEFAULT '{}',
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Users table - users within organizations
|
||||||
|
CREATE TABLE users (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
|
||||||
|
username VARCHAR(100) NOT NULL,
|
||||||
|
email VARCHAR(255),
|
||||||
|
role VARCHAR(50) DEFAULT 'user',
|
||||||
|
settings JSONB DEFAULT '{}',
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
UNIQUE(organization_id, username)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Images table - metadata for generated and uploaded images
|
||||||
|
CREATE TABLE images (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
filename VARCHAR(255) NOT NULL,
|
||||||
|
file_path VARCHAR(500), -- Legacy: local file path (for backward compatibility)
|
||||||
|
minio_key VARCHAR(500), -- MinIO object key
|
||||||
|
url VARCHAR(1000), -- Public or presigned URL to access the image
|
||||||
|
original_prompt TEXT,
|
||||||
|
enhanced_prompt TEXT,
|
||||||
|
model_used VARCHAR(100),
|
||||||
|
file_size BIGINT,
|
||||||
|
content_type VARCHAR(100),
|
||||||
|
category VARCHAR(50) DEFAULT 'generated', -- 'generated', 'references', 'temp'
|
||||||
|
metadata JSONB DEFAULT '{}',
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Sessions table - for tracking user upload sessions
|
||||||
|
CREATE TABLE upload_sessions (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
session_data JSONB NOT NULL,
|
||||||
|
expires_at TIMESTAMP WITH TIME ZONE,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create indexes for better query performance
|
||||||
|
CREATE INDEX idx_users_org_id ON users(organization_id);
|
||||||
|
CREATE INDEX idx_users_username ON users(username);
|
||||||
|
CREATE INDEX idx_images_user_id ON images(user_id);
|
||||||
|
CREATE INDEX idx_images_created_at ON images(created_at);
|
||||||
|
CREATE INDEX idx_images_category ON images(category);
|
||||||
|
CREATE INDEX idx_images_minio_key ON images(minio_key);
|
||||||
|
CREATE INDEX idx_upload_sessions_user_id ON upload_sessions(user_id);
|
||||||
|
CREATE INDEX idx_upload_sessions_expires_at ON upload_sessions(expires_at);
|
||||||
|
|
||||||
|
-- Insert demo organization and user for development/testing
|
||||||
|
INSERT INTO organizations (id, name, slug, settings) VALUES
|
||||||
|
('00000000-0000-0000-0000-000000000001', 'Demo Organization', 'demo', '{"description": "Default demo organization for testing"}');
|
||||||
|
|
||||||
|
INSERT INTO users (id, organization_id, username, email, role, settings) VALUES
|
||||||
|
('00000000-0000-0000-0000-000000000001', '00000000-0000-0000-0000-000000000001', 'guest', 'guest@demo.banatie.app', 'user', '{"description": "Default guest user for testing"}');
|
||||||
|
|
||||||
|
-- Create a function to update updated_at timestamp
|
||||||
|
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
BEGIN
|
||||||
|
NEW.updated_at = NOW();
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ language 'plpgsql';
|
||||||
|
|
||||||
|
-- Create triggers to automatically update updated_at
|
||||||
|
CREATE TRIGGER update_organizations_updated_at
|
||||||
|
BEFORE UPDATE ON organizations
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||||
|
|
||||||
|
CREATE TRIGGER update_users_updated_at
|
||||||
|
BEFORE UPDATE ON users
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||||
|
|
||||||
|
CREATE TRIGGER update_images_updated_at
|
||||||
|
BEFORE UPDATE ON images
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||||
|
|
||||||
|
-- Display initialization completion message
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
RAISE NOTICE 'Banatie database initialization completed successfully!';
|
||||||
|
RAISE NOTICE 'Created tables: organizations, users, images, upload_sessions';
|
||||||
|
RAISE NOTICE 'Created demo organization (id: 00000000-0000-0000-0000-000000000001) with guest user';
|
||||||
|
END $$;
|
||||||
|
|
@ -48,7 +48,7 @@ export const validateGenerateRequest = (
|
||||||
try {
|
try {
|
||||||
enhancementOptions = JSON.parse(enhancementOptions);
|
enhancementOptions = JSON.parse(enhancementOptions);
|
||||||
req.body.enhancementOptions = enhancementOptions;
|
req.body.enhancementOptions = enhancementOptions;
|
||||||
} catch (error) {
|
} catch {
|
||||||
errors.push("enhancementOptions must be valid JSON");
|
errors.push("enhancementOptions must be valid JSON");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { GoogleGenAI } from "@google/genai";
|
import { GoogleGenAI } from "@google/genai";
|
||||||
import mime from "mime";
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const mime = require("mime") as any;
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import {
|
import {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue