mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:21:09 +02:00
✨ feat(chat,picture): add OpenRouter integration and credit system
Chat: - Add OpenRouter as primary AI provider with multiple models - Update chat service with new model configurations - Add model seed data for Llama, DeepSeek, Mistral, Claude, GPT-4o Picture: - Integrate @mana-core/nestjs-integration for credit system - Implement freemium model (3 free generations, then 10 credits) - Migrate storage to @manacore/shared-storage - Add comprehensive project documentation
This commit is contained in:
parent
422fcd6b34
commit
6f74e1d9a6
12 changed files with 878 additions and 468 deletions
|
|
@ -130,12 +130,19 @@ MANADECK_SUPABASE_ANON_KEY=your-supabase-anon-key
|
||||||
|
|
||||||
PICTURE_BACKEND_PORT=3006
|
PICTURE_BACKEND_PORT=3006
|
||||||
PICTURE_BACKEND_URL=http://localhost:3006
|
PICTURE_BACKEND_URL=http://localhost:3006
|
||||||
PICTURE_DATABASE_URL=postgresql://picture:picturepassword@localhost:5434/picture
|
PICTURE_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/picture
|
||||||
|
|
||||||
|
# Replicate API Token for AI image generation
|
||||||
|
PICTURE_REPLICATE_API_TOKEN=r8_QlvkstNhIc6NBX1ktpQ6ibvzOE2d2UQ1Emamd
|
||||||
|
|
||||||
# Storage Configuration (uses MinIO locally, Hetzner in production)
|
# Storage Configuration (uses MinIO locally, Hetzner in production)
|
||||||
# Uses shared S3_* variables from above - no project-specific override needed for local dev
|
# Uses shared S3_* variables from above - no project-specific override needed for local dev
|
||||||
PICTURE_STORAGE_PUBLIC_URL=http://localhost:9000/picture-storage
|
PICTURE_STORAGE_PUBLIC_URL=http://localhost:9000/picture-storage
|
||||||
|
|
||||||
|
# Credit System (staging only - freemium: 3 free images, then credits)
|
||||||
|
PICTURE_APP_ID=picture-app
|
||||||
|
PICTURE_MANA_CORE_SERVICE_KEY=
|
||||||
|
|
||||||
# OAuth (optional - leave empty to disable)
|
# OAuth (optional - leave empty to disable)
|
||||||
PICTURE_GOOGLE_CLIENT_ID=
|
PICTURE_GOOGLE_CLIENT_ID=
|
||||||
PICTURE_APPLE_CLIENT_ID=
|
PICTURE_APPLE_CLIENT_ID=
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ pnpm preview # Preview production build
|
||||||
- **Mobile**: React Native 0.76.7 + Expo SDK 52, NativeWind, Expo Router
|
- **Mobile**: React Native 0.76.7 + Expo SDK 52, NativeWind, Expo Router
|
||||||
- **Web**: SvelteKit 2.x, Svelte 5, Tailwind CSS 4
|
- **Web**: SvelteKit 2.x, Svelte 5, Tailwind CSS 4
|
||||||
- **Landing**: Astro 5.16, Tailwind CSS
|
- **Landing**: Astro 5.16, Tailwind CSS
|
||||||
- **Backend**: NestJS 10, Google Gemini AI, Supabase
|
- **Backend**: NestJS 10, OpenRouter/Gemini AI, Supabase
|
||||||
- **Types**: TypeScript 5.x
|
- **Types**: TypeScript 5.x
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
@ -89,11 +89,12 @@ pnpm preview # Preview production build
|
||||||
#### Backend (.env)
|
#### Backend (.env)
|
||||||
|
|
||||||
```
|
```
|
||||||
GOOGLE_GENAI_API_KEY=...
|
OPENROUTER_API_KEY=... # Get at https://openrouter.ai/keys
|
||||||
|
GOOGLE_GENAI_API_KEY=... # Optional: For Gemini models
|
||||||
SUPABASE_URL=https://...
|
SUPABASE_URL=https://...
|
||||||
SUPABASE_SERVICE_KEY=...
|
SUPABASE_SERVICE_KEY=...
|
||||||
PORT=3002
|
PORT=3002
|
||||||
DEV_BYPASS_AUTH=true # Optional: Skip auth in development
|
DEV_BYPASS_AUTH=true # Optional: Skip auth in development
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Mobile (.env)
|
#### Mobile (.env)
|
||||||
|
|
@ -114,11 +115,33 @@ EXPO_PUBLIC_BACKEND_URL=http://localhost:3001
|
||||||
|
|
||||||
## AI Models Available
|
## AI Models Available
|
||||||
|
|
||||||
| Model ID | Name | Description | Default |
|
### OpenRouter Models (Recommended)
|
||||||
| ------------------------------------ | --------------------- | ------------------------- | ------- |
|
|
||||||
| 550e8400-e29b-41d4-a716-446655440101 | Gemini 2.5 Flash | Fast, efficient responses | Yes |
|
| Model ID | Name | Price | Best For |
|
||||||
| 550e8400-e29b-41d4-a716-446655440102 | Gemini 2.0 Flash-Lite | Ultra-lightweight model | No |
|
| -------- | ---- | ----- | -------- |
|
||||||
| 550e8400-e29b-41d4-a716-446655440103 | Gemini 2.5 Pro | Most capable model | No |
|
| ...440201 | Llama 3.1 8B | $0.05/M | Everyday tasks, cheap |
|
||||||
|
| ...440202 | Llama 3.1 70B | $0.35/M | Complex reasoning |
|
||||||
|
| ...440203 | DeepSeek V3 | $0.14/M | Reasoning at low cost |
|
||||||
|
| ...440204 | Mistral Small | $0.10/M | General tasks |
|
||||||
|
| ...440205 | Claude 3.5 Sonnet | $3/M | Best quality |
|
||||||
|
| ...440206 | GPT-4o Mini | $0.15/M | Balanced performance |
|
||||||
|
|
||||||
|
### Google Gemini Models
|
||||||
|
|
||||||
|
| Model ID | Name | Description | Default |
|
||||||
|
| -------- | ---- | ----------- | ------- |
|
||||||
|
| ...440101 | Gemini 2.5 Flash | Fast, efficient responses | Yes |
|
||||||
|
| ...440102 | Gemini 2.0 Flash-Lite | Ultra-lightweight model | No |
|
||||||
|
| ...440103 | Gemini 2.5 Pro | Most capable model | No |
|
||||||
|
|
||||||
|
## OpenRouter Setup
|
||||||
|
|
||||||
|
To enable OpenRouter models:
|
||||||
|
|
||||||
|
- [ ] Get API key at https://openrouter.ai/keys
|
||||||
|
- [ ] Add `OPENROUTER_API_KEY=sk-or-v1-xxx` to `apps/chat/apps/backend/.env`
|
||||||
|
- [ ] Re-seed database: `pnpm --filter @chat/backend db:seed`
|
||||||
|
- [ ] Test: `pnpm dev:chat:backend`
|
||||||
|
|
||||||
## Important Notes
|
## Important Notes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,11 @@
|
||||||
# Azure OpenAI Configuration
|
# OpenRouter Configuration (Recommended - multi-model access)
|
||||||
|
# Get your API key at https://openrouter.ai/keys
|
||||||
|
OPENROUTER_API_KEY=your-openrouter-api-key
|
||||||
|
|
||||||
|
# Google Gemini Configuration
|
||||||
|
GOOGLE_GENAI_API_KEY=your-google-api-key
|
||||||
|
|
||||||
|
# Azure OpenAI Configuration (Optional)
|
||||||
AZURE_OPENAI_ENDPOINT=https://your-azure-openai-endpoint.openai.azure.com
|
AZURE_OPENAI_ENDPOINT=https://your-azure-openai-endpoint.openai.azure.com
|
||||||
AZURE_OPENAI_API_KEY=your-api-key-here
|
AZURE_OPENAI_API_KEY=your-api-key-here
|
||||||
AZURE_OPENAI_API_VERSION=2024-12-01-preview
|
AZURE_OPENAI_API_VERSION=2024-12-01-preview
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { ConfigService } from '@nestjs/config';
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
import { AsyncResult, ok, err, ValidationError, ServiceError } from '@manacore/shared-errors';
|
import { AsyncResult, ok, err, ValidationError, ServiceError } from '@manacore/shared-errors';
|
||||||
import { GoogleGenerativeAI } from '@google/generative-ai';
|
import { GoogleGenerativeAI } from '@google/generative-ai';
|
||||||
|
import OpenAI from 'openai';
|
||||||
import { DATABASE_CONNECTION } from '../db/database.module';
|
import { DATABASE_CONNECTION } from '../db/database.module';
|
||||||
import { Database } from '../db/connection';
|
import { Database } from '../db/connection';
|
||||||
import { models } from '../db/schema/models.schema';
|
import { models } from '../db/schema/models.schema';
|
||||||
|
|
@ -19,6 +20,8 @@ export class ChatService {
|
||||||
private readonly azureApiVersion: string;
|
private readonly azureApiVersion: string;
|
||||||
// Google Gemini config
|
// Google Gemini config
|
||||||
private readonly geminiClient: GoogleGenerativeAI | null = null;
|
private readonly geminiClient: GoogleGenerativeAI | null = null;
|
||||||
|
// OpenRouter config
|
||||||
|
private readonly openRouterClient: OpenAI | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private configService: ConfigService,
|
private configService: ConfigService,
|
||||||
|
|
@ -41,6 +44,22 @@ export class ChatService {
|
||||||
this.logger.warn('GOOGLE_GENAI_API_KEY is not set - Gemini models unavailable');
|
this.logger.warn('GOOGLE_GENAI_API_KEY is not set - Gemini models unavailable');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OpenRouter setup
|
||||||
|
const openRouterApiKey = this.configService.get<string>('OPENROUTER_API_KEY');
|
||||||
|
if (openRouterApiKey) {
|
||||||
|
this.openRouterClient = new OpenAI({
|
||||||
|
baseURL: 'https://openrouter.ai/api/v1',
|
||||||
|
apiKey: openRouterApiKey,
|
||||||
|
defaultHeaders: {
|
||||||
|
'HTTP-Referer': this.configService.get<string>('APP_URL') || 'http://localhost:3002',
|
||||||
|
'X-Title': 'Mana Chat',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.logger.log('OpenRouter client initialized');
|
||||||
|
} else {
|
||||||
|
this.logger.warn('OPENROUTER_API_KEY is not set - OpenRouter models unavailable');
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.azureApiKey) {
|
if (!this.azureApiKey) {
|
||||||
this.logger.warn('AZURE_OPENAI_API_KEY is not set - Azure models unavailable');
|
this.logger.warn('AZURE_OPENAI_API_KEY is not set - Azure models unavailable');
|
||||||
}
|
}
|
||||||
|
|
@ -84,6 +103,8 @@ export class ChatService {
|
||||||
// Route to appropriate provider
|
// Route to appropriate provider
|
||||||
if (model.provider === 'gemini') {
|
if (model.provider === 'gemini') {
|
||||||
return this.createGeminiCompletion(model, dto);
|
return this.createGeminiCompletion(model, dto);
|
||||||
|
} else if (model.provider === 'openrouter') {
|
||||||
|
return this.createOpenRouterCompletion(model, dto);
|
||||||
} else {
|
} else {
|
||||||
return this.createAzureCompletion(model, dto);
|
return this.createAzureCompletion(model, dto);
|
||||||
}
|
}
|
||||||
|
|
@ -250,4 +271,62 @@ export class ChatService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async createOpenRouterCompletion(
|
||||||
|
model: Model,
|
||||||
|
dto: ChatCompletionDto
|
||||||
|
): AsyncResult<ChatCompletionResponseDto> {
|
||||||
|
if (!this.openRouterClient) {
|
||||||
|
return err(ServiceError.externalError('OpenRouter', 'OpenRouter client not configured'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = model.parameters as {
|
||||||
|
model?: string;
|
||||||
|
temperature?: number;
|
||||||
|
max_tokens?: number;
|
||||||
|
} | null;
|
||||||
|
|
||||||
|
const modelName = params?.model || 'meta-llama/llama-3.1-8b-instruct';
|
||||||
|
const temperature = dto.temperature ?? params?.temperature ?? 0.7;
|
||||||
|
const maxTokens = dto.maxTokens ?? params?.max_tokens ?? 4096;
|
||||||
|
|
||||||
|
this.logger.log(`Sending request to OpenRouter model: ${modelName}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.openRouterClient.chat.completions.create({
|
||||||
|
model: modelName,
|
||||||
|
messages: dto.messages.map((msg) => ({
|
||||||
|
role: msg.role as 'system' | 'user' | 'assistant',
|
||||||
|
content: msg.content,
|
||||||
|
})),
|
||||||
|
temperature,
|
||||||
|
max_tokens: maxTokens,
|
||||||
|
});
|
||||||
|
|
||||||
|
const messageContent = response.choices?.[0]?.message?.content;
|
||||||
|
|
||||||
|
if (!messageContent) {
|
||||||
|
this.logger.warn('No message content in OpenRouter response');
|
||||||
|
return err(ServiceError.generationFailed('OpenRouter', 'No response generated'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok({
|
||||||
|
content: messageContent,
|
||||||
|
usage: {
|
||||||
|
prompt_tokens: response.usage?.prompt_tokens || 0,
|
||||||
|
completion_tokens: response.usage?.completion_tokens || 0,
|
||||||
|
total_tokens: response.usage?.total_tokens || 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error('Error calling OpenRouter API', error);
|
||||||
|
return err(
|
||||||
|
ServiceError.generationFailed(
|
||||||
|
'OpenRouter',
|
||||||
|
error instanceof Error ? error.message : 'Unknown error',
|
||||||
|
error instanceof Error ? error : undefined
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,87 @@ async function seed() {
|
||||||
isDefault: false,
|
isDefault: false,
|
||||||
},
|
},
|
||||||
// ============================================
|
// ============================================
|
||||||
|
// OpenRouter Models (Multi-provider, cost-effective)
|
||||||
|
// ============================================
|
||||||
|
{
|
||||||
|
id: '550e8400-e29b-41d4-a716-446655440201',
|
||||||
|
name: 'Llama 3.1 8B',
|
||||||
|
description: 'Fast & cheap - great for everyday tasks ($0.05/M tokens)',
|
||||||
|
provider: 'openrouter',
|
||||||
|
parameters: {
|
||||||
|
model: 'meta-llama/llama-3.1-8b-instruct',
|
||||||
|
temperature: 0.7,
|
||||||
|
max_tokens: 4096,
|
||||||
|
},
|
||||||
|
isActive: true,
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '550e8400-e29b-41d4-a716-446655440202',
|
||||||
|
name: 'Llama 3.1 70B',
|
||||||
|
description: 'Powerful open model - complex reasoning ($0.35/M tokens)',
|
||||||
|
provider: 'openrouter',
|
||||||
|
parameters: {
|
||||||
|
model: 'meta-llama/llama-3.1-70b-instruct',
|
||||||
|
temperature: 0.7,
|
||||||
|
max_tokens: 8192,
|
||||||
|
},
|
||||||
|
isActive: true,
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '550e8400-e29b-41d4-a716-446655440203',
|
||||||
|
name: 'DeepSeek V3',
|
||||||
|
description: 'Excellent reasoning at low cost ($0.14/M tokens)',
|
||||||
|
provider: 'openrouter',
|
||||||
|
parameters: {
|
||||||
|
model: 'deepseek/deepseek-chat',
|
||||||
|
temperature: 0.7,
|
||||||
|
max_tokens: 8192,
|
||||||
|
},
|
||||||
|
isActive: true,
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '550e8400-e29b-41d4-a716-446655440204',
|
||||||
|
name: 'Mistral Small',
|
||||||
|
description: 'Fast European model - good for general tasks ($0.10/M tokens)',
|
||||||
|
provider: 'openrouter',
|
||||||
|
parameters: {
|
||||||
|
model: 'mistralai/mistral-small-24b-instruct-2501',
|
||||||
|
temperature: 0.7,
|
||||||
|
max_tokens: 4096,
|
||||||
|
},
|
||||||
|
isActive: true,
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '550e8400-e29b-41d4-a716-446655440205',
|
||||||
|
name: 'Claude 3.5 Sonnet',
|
||||||
|
description: 'Best overall quality - coding & analysis ($3/M tokens)',
|
||||||
|
provider: 'openrouter',
|
||||||
|
parameters: {
|
||||||
|
model: 'anthropic/claude-3.5-sonnet',
|
||||||
|
temperature: 0.7,
|
||||||
|
max_tokens: 8192,
|
||||||
|
},
|
||||||
|
isActive: true,
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '550e8400-e29b-41d4-a716-446655440206',
|
||||||
|
name: 'GPT-4o Mini',
|
||||||
|
description: 'OpenAI fast model - balanced performance ($0.15/M tokens)',
|
||||||
|
provider: 'openrouter',
|
||||||
|
parameters: {
|
||||||
|
model: 'openai/gpt-4o-mini',
|
||||||
|
temperature: 0.7,
|
||||||
|
max_tokens: 4096,
|
||||||
|
},
|
||||||
|
isActive: true,
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
// ============================================
|
||||||
// Azure OpenAI GPT-5 Family (Inactive - no deployment)
|
// Azure OpenAI GPT-5 Family (Inactive - no deployment)
|
||||||
// ============================================
|
// ============================================
|
||||||
{
|
{
|
||||||
|
|
|
||||||
194
apps/picture/CLAUDE.md
Normal file
194
apps/picture/CLAUDE.md
Normal file
|
|
@ -0,0 +1,194 @@
|
||||||
|
# Picture App - CLAUDE.md
|
||||||
|
|
||||||
|
AI image generation app using Replicate API with freemium credit system.
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
apps/picture/
|
||||||
|
├── apps/
|
||||||
|
│ ├── backend/ # NestJS API (port 3006)
|
||||||
|
│ ├── mobile/ # Expo React Native app
|
||||||
|
│ ├── web/ # SvelteKit web app
|
||||||
|
│ └── landing/ # Astro marketing page
|
||||||
|
└── packages/ # Shared code
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# From monorepo root
|
||||||
|
pnpm dev:picture:full # Start backend + web + auto DB setup
|
||||||
|
|
||||||
|
# Individual apps
|
||||||
|
pnpm --filter @picture/backend dev # Backend only (port 3006)
|
||||||
|
pnpm --filter @picture/web dev # Web only
|
||||||
|
pnpm --filter @picture/mobile dev # Mobile only
|
||||||
|
```
|
||||||
|
|
||||||
|
## Backend Architecture
|
||||||
|
|
||||||
|
### Key Services
|
||||||
|
|
||||||
|
| Service | Purpose |
|
||||||
|
|---------|---------|
|
||||||
|
| `GenerateService` | AI image generation with freemium/credit logic |
|
||||||
|
| `ReplicateService` | Replicate API integration |
|
||||||
|
| `StorageService` | MinIO/S3 storage via `@manacore/shared-storage` |
|
||||||
|
| `CreditClientService` | Credit system via `@mana-core/nestjs-integration` |
|
||||||
|
|
||||||
|
### Freemium Model
|
||||||
|
|
||||||
|
- **Free tier**: 3 free generations per user
|
||||||
|
- **Paid tier**: 10 credits per generation
|
||||||
|
- **Enforcement**: Only in staging (`NODE_ENV=staging`)
|
||||||
|
- **Development**: Fail-open (no credit enforcement)
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
| Variable | Description | Required |
|
||||||
|
|----------|-------------|----------|
|
||||||
|
| `REPLICATE_API_TOKEN` | Replicate API key | Yes |
|
||||||
|
| `DATABASE_URL` | PostgreSQL connection | Yes |
|
||||||
|
| `S3_ENDPOINT` | MinIO/S3 endpoint | Yes |
|
||||||
|
| `MANA_CORE_AUTH_URL` | Auth service URL | Yes |
|
||||||
|
| `MANA_CORE_SERVICE_KEY` | Service key for credits | Staging only |
|
||||||
|
| `APP_ID` | App identifier | Yes |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TODO List
|
||||||
|
|
||||||
|
### Testing Required
|
||||||
|
|
||||||
|
- [ ] **Test freemium flow with new user**
|
||||||
|
- Create new user ID and verify 3 free generations work
|
||||||
|
- Verify `freeGenerationsRemaining` decrements correctly (3 → 2 → 1 → 0)
|
||||||
|
- Verify 4th generation still works in development (fail-open)
|
||||||
|
|
||||||
|
- [ ] **Test staging credit enforcement**
|
||||||
|
- Set `NODE_ENV=staging` and test credit check
|
||||||
|
- Verify HTTP 402 returned when credits insufficient
|
||||||
|
- Test with valid `MANA_CORE_SERVICE_KEY`
|
||||||
|
|
||||||
|
- [ ] **Test async generation (webhook mode)**
|
||||||
|
- Test generation without `waitForResult: true`
|
||||||
|
- Verify webhook receives completion callback
|
||||||
|
- Verify credits consumed on webhook success
|
||||||
|
|
||||||
|
- [ ] **Test error handling**
|
||||||
|
- Test with invalid model ID
|
||||||
|
- Test with invalid Replicate API token
|
||||||
|
- Test storage upload failures
|
||||||
|
|
||||||
|
- [ ] **Integration tests**
|
||||||
|
- Write Jest tests for `GenerateService`
|
||||||
|
- Mock `CreditClientService` calls
|
||||||
|
- Test all generation paths (free/paid, sync/async)
|
||||||
|
|
||||||
|
### Features to Implement
|
||||||
|
|
||||||
|
- [ ] **Add credit balance endpoint**
|
||||||
|
- GET `/api/v1/credits/balance` - Return user's credit balance
|
||||||
|
- Use `CreditClientService.getBalance()`
|
||||||
|
|
||||||
|
- [ ] **Add generation history endpoint**
|
||||||
|
- GET `/api/v1/generate/history` - User's generation history
|
||||||
|
- Include credits used per generation
|
||||||
|
|
||||||
|
- [ ] **Improve error messages**
|
||||||
|
- Add proper error codes for credit failures
|
||||||
|
- Return helpful messages for insufficient credits
|
||||||
|
|
||||||
|
- [ ] **Rate limiting**
|
||||||
|
- Add rate limits for generation endpoints
|
||||||
|
- Prevent abuse of free tier
|
||||||
|
|
||||||
|
### Web App Tasks
|
||||||
|
|
||||||
|
- [ ] **Show free generations remaining**
|
||||||
|
- Display counter in UI
|
||||||
|
- Show warning when approaching limit
|
||||||
|
|
||||||
|
- [ ] **Credit purchase flow**
|
||||||
|
- Integrate with mana-core credit purchase
|
||||||
|
- Show credit balance in header
|
||||||
|
|
||||||
|
- [ ] **Generation queue UI**
|
||||||
|
- Show pending generations
|
||||||
|
- Poll for status updates
|
||||||
|
|
||||||
|
### Mobile App Tasks
|
||||||
|
|
||||||
|
- [ ] **Implement generation screen**
|
||||||
|
- Model selection
|
||||||
|
- Prompt input with suggestions
|
||||||
|
- Generation progress indicator
|
||||||
|
|
||||||
|
- [ ] **Gallery view**
|
||||||
|
- Grid view of user's generated images
|
||||||
|
- Favorites functionality
|
||||||
|
|
||||||
|
### DevOps Tasks
|
||||||
|
|
||||||
|
- [ ] **Staging deployment**
|
||||||
|
- Deploy backend to staging server
|
||||||
|
- Configure `MANA_CORE_SERVICE_KEY` in staging
|
||||||
|
- Test credit system end-to-end
|
||||||
|
|
||||||
|
- [ ] **Monitoring**
|
||||||
|
- Add logging for credit operations
|
||||||
|
- Track generation success/failure rates
|
||||||
|
- Monitor Replicate API usage
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API Endpoints
|
||||||
|
|
||||||
|
### Generate
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generate image (sync)
|
||||||
|
POST /api/v1/generate
|
||||||
|
{
|
||||||
|
"prompt": "A beautiful sunset",
|
||||||
|
"modelId": "uuid",
|
||||||
|
"waitForResult": true
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check status
|
||||||
|
GET /api/v1/generate/:id/status
|
||||||
|
|
||||||
|
# Cancel generation
|
||||||
|
DELETE /api/v1/generate/:id
|
||||||
|
|
||||||
|
# Webhook (internal)
|
||||||
|
POST /api/v1/generate/webhook
|
||||||
|
```
|
||||||
|
|
||||||
|
### Models
|
||||||
|
|
||||||
|
```bash
|
||||||
|
GET /api/v1/models # List all models
|
||||||
|
GET /api/v1/models/:id # Get model details
|
||||||
|
```
|
||||||
|
|
||||||
|
### Images
|
||||||
|
|
||||||
|
```bash
|
||||||
|
GET /api/v1/images # List user's images
|
||||||
|
GET /api/v1/images/:id # Get image details
|
||||||
|
DELETE /api/v1/images/:id # Delete image
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recent Changes
|
||||||
|
|
||||||
|
### 2025-12-10: Credit System Integration
|
||||||
|
|
||||||
|
- Added `@mana-core/nestjs-integration` for credit system
|
||||||
|
- Implemented freemium model (3 free, then 10 credits)
|
||||||
|
- Credit enforcement only in staging environment
|
||||||
|
- Updated `GenerateService` with `checkGenerationAccess()`
|
||||||
|
- Response includes `freeGenerationsRemaining` count
|
||||||
|
|
@ -19,8 +19,10 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.700.0",
|
"@aws-sdk/client-s3": "^3.700.0",
|
||||||
|
"@mana-core/nestjs-integration": "workspace:*",
|
||||||
"@manacore/shared-errors": "workspace:*",
|
"@manacore/shared-errors": "workspace:*",
|
||||||
"@manacore/shared-nestjs-auth": "workspace:*",
|
"@manacore/shared-nestjs-auth": "workspace:*",
|
||||||
|
"@manacore/shared-storage": "workspace:*",
|
||||||
"@nestjs/common": "^10.4.15",
|
"@nestjs/common": "^10.4.15",
|
||||||
"@nestjs/config": "^3.3.0",
|
"@nestjs/config": "^3.3.0",
|
||||||
"@nestjs/core": "^10.4.15",
|
"@nestjs/core": "^10.4.15",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
|
import { ManaCoreModule } from '@mana-core/nestjs-integration';
|
||||||
import { DatabaseModule } from './db/database.module';
|
import { DatabaseModule } from './db/database.module';
|
||||||
import { HealthModule } from './health/health.module';
|
import { HealthModule } from './health/health.module';
|
||||||
import { ModelModule } from './model/model.module';
|
import { ModelModule } from './model/model.module';
|
||||||
|
|
@ -19,6 +20,16 @@ import { BatchModule } from './batch/batch.module';
|
||||||
isGlobal: true,
|
isGlobal: true,
|
||||||
envFilePath: '.env',
|
envFilePath: '.env',
|
||||||
}),
|
}),
|
||||||
|
ManaCoreModule.forRootAsync({
|
||||||
|
imports: [ConfigModule],
|
||||||
|
useFactory: (configService: ConfigService) => ({
|
||||||
|
appId: configService.get('APP_ID', 'picture-app'),
|
||||||
|
serviceKey: configService.get('MANA_CORE_SERVICE_KEY', ''),
|
||||||
|
authUrl: configService.get('MANA_CORE_AUTH_URL', 'http://localhost:3001'),
|
||||||
|
debug: configService.get('NODE_ENV') === 'development',
|
||||||
|
}),
|
||||||
|
inject: [ConfigService],
|
||||||
|
}),
|
||||||
DatabaseModule,
|
DatabaseModule,
|
||||||
HealthModule,
|
HealthModule,
|
||||||
ModelModule,
|
ModelModule,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,15 @@
|
||||||
import { Injectable, Inject, NotFoundException, ForbiddenException, Logger } from '@nestjs/common';
|
import {
|
||||||
|
Injectable,
|
||||||
|
Inject,
|
||||||
|
NotFoundException,
|
||||||
|
ForbiddenException,
|
||||||
|
HttpException,
|
||||||
|
HttpStatus,
|
||||||
|
Logger,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq, and, count } from 'drizzle-orm';
|
||||||
|
import { CreditClientService } from '@mana-core/nestjs-integration';
|
||||||
import { DATABASE_CONNECTION } from '../db/database.module';
|
import { DATABASE_CONNECTION } from '../db/database.module';
|
||||||
import { Database } from '../db/connection';
|
import { Database } from '../db/connection';
|
||||||
import { imageGenerations, images, models } from '../db/schema';
|
import { imageGenerations, images, models } from '../db/schema';
|
||||||
|
|
@ -9,25 +18,104 @@ import { ReplicateService, GenerationParams } from './replicate.service';
|
||||||
import { StorageService } from '../upload/storage.service';
|
import { StorageService } from '../upload/storage.service';
|
||||||
import { GenerateImageDto } from './dto/generate.dto';
|
import { GenerateImageDto } from './dto/generate.dto';
|
||||||
|
|
||||||
|
const FREE_GENERATIONS_LIMIT = 3;
|
||||||
|
const CREDITS_PER_GENERATION = 10;
|
||||||
|
|
||||||
export interface GenerateResponse {
|
export interface GenerateResponse {
|
||||||
generationId: string;
|
generationId: string;
|
||||||
status: string;
|
status: string;
|
||||||
image?: Image;
|
image?: Image;
|
||||||
|
creditsUsed?: number;
|
||||||
|
freeGenerationsRemaining?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GenerateService {
|
export class GenerateService {
|
||||||
private readonly logger = new Logger(GenerateService.name);
|
private readonly logger = new Logger(GenerateService.name);
|
||||||
private readonly webhookBaseUrl: string;
|
private readonly webhookBaseUrl: string;
|
||||||
|
private readonly isStaging: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DATABASE_CONNECTION) private readonly db: Database,
|
@Inject(DATABASE_CONNECTION) private readonly db: Database,
|
||||||
private readonly replicateService: ReplicateService,
|
private readonly replicateService: ReplicateService,
|
||||||
private readonly storageService: StorageService,
|
private readonly storageService: StorageService,
|
||||||
|
private readonly creditClient: CreditClientService,
|
||||||
private configService: ConfigService
|
private configService: ConfigService
|
||||||
) {
|
) {
|
||||||
this.webhookBaseUrl =
|
this.webhookBaseUrl =
|
||||||
this.configService.get<string>('WEBHOOK_BASE_URL') || 'http://localhost:3003';
|
this.configService.get<string>('WEBHOOK_BASE_URL') || 'http://localhost:3003';
|
||||||
|
// Freemium/credit system only enforced in staging
|
||||||
|
this.isStaging = this.configService.get<string>('NODE_ENV') === 'staging';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get count of completed generations for a user
|
||||||
|
*/
|
||||||
|
private async getUserGenerationCount(userId: string): Promise<number> {
|
||||||
|
const result = await this.db
|
||||||
|
.select({ count: count() })
|
||||||
|
.from(imageGenerations)
|
||||||
|
.where(and(eq(imageGenerations.userId, userId), eq(imageGenerations.status, 'completed')));
|
||||||
|
return result[0]?.count ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if user can generate (has free generations or credits)
|
||||||
|
* Returns: { canGenerate, isFree, freeRemaining, creditsRequired }
|
||||||
|
*/
|
||||||
|
async checkGenerationAccess(userId: string): Promise<{
|
||||||
|
canGenerate: boolean;
|
||||||
|
isFree: boolean;
|
||||||
|
freeGenerationsRemaining: number;
|
||||||
|
creditsRequired: number;
|
||||||
|
currentBalance?: number;
|
||||||
|
}> {
|
||||||
|
const completedCount = await this.getUserGenerationCount(userId);
|
||||||
|
const freeRemaining = Math.max(0, FREE_GENERATIONS_LIMIT - completedCount);
|
||||||
|
|
||||||
|
// If user has free generations, they can proceed
|
||||||
|
if (freeRemaining > 0) {
|
||||||
|
return {
|
||||||
|
canGenerate: true,
|
||||||
|
isFree: true,
|
||||||
|
freeGenerationsRemaining: freeRemaining,
|
||||||
|
creditsRequired: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// No free generations - check credits (only in staging)
|
||||||
|
if (!this.isStaging) {
|
||||||
|
// In development/production without credit enforcement, allow generation
|
||||||
|
return {
|
||||||
|
canGenerate: true,
|
||||||
|
isFree: false,
|
||||||
|
freeGenerationsRemaining: 0,
|
||||||
|
creditsRequired: CREDITS_PER_GENERATION,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// In staging, check actual credit balance
|
||||||
|
try {
|
||||||
|
const balance = await this.creditClient.getBalance(userId);
|
||||||
|
const hasEnoughCredits = balance.balance >= CREDITS_PER_GENERATION;
|
||||||
|
|
||||||
|
return {
|
||||||
|
canGenerate: hasEnoughCredits,
|
||||||
|
isFree: false,
|
||||||
|
freeGenerationsRemaining: 0,
|
||||||
|
creditsRequired: CREDITS_PER_GENERATION,
|
||||||
|
currentBalance: balance.balance,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.warn(`Failed to check credit balance for user ${userId}`, error);
|
||||||
|
// On error, allow generation (fail open for better UX)
|
||||||
|
return {
|
||||||
|
canGenerate: true,
|
||||||
|
isFree: false,
|
||||||
|
freeGenerationsRemaining: 0,
|
||||||
|
creditsRequired: CREDITS_PER_GENERATION,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -35,6 +123,16 @@ export class GenerateService {
|
||||||
*/
|
*/
|
||||||
async generateImage(userId: string, dto: GenerateImageDto): Promise<GenerateResponse> {
|
async generateImage(userId: string, dto: GenerateImageDto): Promise<GenerateResponse> {
|
||||||
try {
|
try {
|
||||||
|
// Check if user can generate (freemium/credit check)
|
||||||
|
const access = await this.checkGenerationAccess(userId);
|
||||||
|
|
||||||
|
if (!access.canGenerate) {
|
||||||
|
throw new HttpException(
|
||||||
|
`Insufficient credits. You need ${access.creditsRequired} credits. Current balance: ${access.currentBalance ?? 0}`,
|
||||||
|
HttpStatus.PAYMENT_REQUIRED
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Get model info
|
// Get model info
|
||||||
const modelResult = await this.db
|
const modelResult = await this.db
|
||||||
.select()
|
.select()
|
||||||
|
|
@ -70,6 +168,7 @@ export class GenerateService {
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
const generation = generationResult[0];
|
const generation = generationResult[0];
|
||||||
|
const isFreeGeneration = access.isFree;
|
||||||
|
|
||||||
// Build generation params
|
// Build generation params
|
||||||
const generationParams: GenerationParams = {
|
const generationParams: GenerationParams = {
|
||||||
|
|
@ -89,13 +188,25 @@ export class GenerateService {
|
||||||
|
|
||||||
// If waitForResult is true, use synchronous generation with polling
|
// If waitForResult is true, use synchronous generation with polling
|
||||||
if (dto.waitForResult) {
|
if (dto.waitForResult) {
|
||||||
return this.generateSync(generation, generationParams);
|
const result = await this.generateSync(generation, generationParams);
|
||||||
|
|
||||||
|
// Consume credits after successful generation (if not free)
|
||||||
|
if (result.status === 'completed' && !isFreeGeneration && this.isStaging) {
|
||||||
|
await this.consumeCreditsForGeneration(userId, generation.id);
|
||||||
|
result.creditsUsed = CREDITS_PER_GENERATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add free generations remaining info
|
||||||
|
const newAccess = await this.checkGenerationAccess(userId);
|
||||||
|
result.freeGenerationsRemaining = newAccess.freeGenerationsRemaining;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise use async generation with webhook
|
// Otherwise use async generation with webhook (credits consumed on webhook completion)
|
||||||
return this.generateAsync(generation, model, generationParams);
|
return this.generateAsync(generation, model, generationParams, isFreeGeneration);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof NotFoundException) {
|
if (error instanceof NotFoundException || error instanceof HttpException) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
this.logger.error('Error generating image', error);
|
this.logger.error('Error generating image', error);
|
||||||
|
|
@ -103,6 +214,24 @@ export class GenerateService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Consume credits for a generation
|
||||||
|
*/
|
||||||
|
private async consumeCreditsForGeneration(userId: string, generationId: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
await this.creditClient.consumeCredits(
|
||||||
|
userId,
|
||||||
|
'image_generation',
|
||||||
|
CREDITS_PER_GENERATION,
|
||||||
|
`Image generation: ${generationId}`
|
||||||
|
);
|
||||||
|
this.logger.log(`Consumed ${CREDITS_PER_GENERATION} credits for user ${userId}`);
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(`Failed to consume credits for generation ${generationId}`, error);
|
||||||
|
// Don't fail the generation if credit consumption fails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synchronous generation - polls until complete
|
* Synchronous generation - polls until complete
|
||||||
*/
|
*/
|
||||||
|
|
@ -200,7 +329,8 @@ export class GenerateService {
|
||||||
private async generateAsync(
|
private async generateAsync(
|
||||||
generation: ImageGeneration,
|
generation: ImageGeneration,
|
||||||
model: any,
|
model: any,
|
||||||
params: GenerationParams
|
params: GenerationParams,
|
||||||
|
isFreeGeneration: boolean
|
||||||
): Promise<GenerateResponse> {
|
): Promise<GenerateResponse> {
|
||||||
try {
|
try {
|
||||||
const webhookUrl = `${this.webhookBaseUrl}/api/generate/webhook`;
|
const webhookUrl = `${this.webhookBaseUrl}/api/generate/webhook`;
|
||||||
|
|
@ -212,12 +342,15 @@ export class GenerateService {
|
||||||
webhookUrl
|
webhookUrl
|
||||||
);
|
);
|
||||||
|
|
||||||
// Update generation with prediction ID
|
// Update generation with prediction ID and free generation flag (in metadata)
|
||||||
await this.db
|
await this.db
|
||||||
.update(imageGenerations)
|
.update(imageGenerations)
|
||||||
.set({
|
.set({
|
||||||
replicatePredictionId: prediction.id,
|
replicatePredictionId: prediction.id,
|
||||||
status: 'processing',
|
status: 'processing',
|
||||||
|
// Store isFreeGeneration in a way that can be retrieved in webhook
|
||||||
|
// We'll use the errorMessage field temporarily for metadata (cleared on success)
|
||||||
|
errorMessage: isFreeGeneration ? 'FREE_GENERATION' : null,
|
||||||
})
|
})
|
||||||
.where(eq(imageGenerations.id, generation.id));
|
.where(eq(imageGenerations.id, generation.id));
|
||||||
|
|
||||||
|
|
@ -401,8 +534,16 @@ export class GenerateService {
|
||||||
|
|
||||||
const generation = result[0];
|
const generation = result[0];
|
||||||
|
|
||||||
|
// Check if this was a free generation (stored in errorMessage field temporarily)
|
||||||
|
const isFreeGeneration = generation.errorMessage === 'FREE_GENERATION';
|
||||||
|
|
||||||
if (status === 'succeeded' && output) {
|
if (status === 'succeeded' && output) {
|
||||||
await this.processCompletedGeneration(generation, output);
|
await this.processCompletedGeneration(generation, output);
|
||||||
|
|
||||||
|
// Consume credits for paid generations in staging
|
||||||
|
if (!isFreeGeneration && this.isStaging) {
|
||||||
|
await this.consumeCreditsForGeneration(generation.userId, generation.id);
|
||||||
|
}
|
||||||
} else if (status === 'failed') {
|
} else if (status === 'failed') {
|
||||||
await this.db
|
await this.db
|
||||||
.update(imageGenerations)
|
.update(imageGenerations)
|
||||||
|
|
|
||||||
|
|
@ -1,80 +1,32 @@
|
||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import {
|
import {
|
||||||
S3Client,
|
createPictureStorage,
|
||||||
PutObjectCommand,
|
StorageClient,
|
||||||
DeleteObjectCommand,
|
generateUserFileKey,
|
||||||
GetObjectCommand,
|
getContentType,
|
||||||
} from '@aws-sdk/client-s3';
|
} from '@manacore/shared-storage';
|
||||||
import * as fs from 'fs/promises';
|
|
||||||
import * as path from 'path';
|
|
||||||
|
|
||||||
export type StorageMode = 'local' | 's3';
|
export type StorageMode = 's3';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class StorageService {
|
export class StorageService implements OnModuleInit {
|
||||||
private readonly logger = new Logger(StorageService.name);
|
private readonly logger = new Logger(StorageService.name);
|
||||||
private mode: StorageMode;
|
private storage!: StorageClient;
|
||||||
private s3Client: S3Client | null = null;
|
private publicUrl: string;
|
||||||
private readonly bucket: string;
|
|
||||||
private readonly localStoragePath: string;
|
|
||||||
private readonly publicUrlBase: string;
|
|
||||||
|
|
||||||
constructor(private configService: ConfigService) {
|
constructor(private configService: ConfigService) {
|
||||||
// Determine storage mode from environment
|
// Get public URL from config
|
||||||
const storageMode = this.configService.get<string>('STORAGE_MODE', 'local');
|
this.publicUrl = this.configService.get<string>(
|
||||||
this.mode = storageMode === 's3' ? 's3' : 'local';
|
|
||||||
|
|
||||||
// S3 configuration (Hetzner Object Storage is S3-compatible)
|
|
||||||
const s3Endpoint = this.configService.get<string>('S3_ENDPOINT');
|
|
||||||
const s3Region = this.configService.get<string>('S3_REGION', 'eu-central-1');
|
|
||||||
const s3AccessKey = this.configService.get<string>('S3_ACCESS_KEY');
|
|
||||||
const s3SecretKey = this.configService.get<string>('S3_SECRET_KEY');
|
|
||||||
this.bucket = this.configService.get<string>('S3_BUCKET', 'picture-uploads');
|
|
||||||
|
|
||||||
// Local storage configuration
|
|
||||||
this.localStoragePath = this.configService.get<string>(
|
|
||||||
'LOCAL_STORAGE_PATH',
|
|
||||||
path.join(process.cwd(), 'uploads')
|
|
||||||
);
|
|
||||||
|
|
||||||
// Public URL base for serving files
|
|
||||||
const backendUrl = this.configService.get<string>('BACKEND_URL', 'http://localhost:3003');
|
|
||||||
this.publicUrlBase = this.configService.get<string>(
|
|
||||||
'STORAGE_PUBLIC_URL',
|
'STORAGE_PUBLIC_URL',
|
||||||
this.mode === 'local' ? `${backendUrl}/uploads` : `https://${this.bucket}.${s3Endpoint}`
|
'http://localhost:9000/picture-storage'
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.mode === 's3') {
|
|
||||||
if (s3Endpoint && s3AccessKey && s3SecretKey) {
|
|
||||||
this.s3Client = new S3Client({
|
|
||||||
endpoint: s3Endpoint.startsWith('http') ? s3Endpoint : `https://${s3Endpoint}`,
|
|
||||||
region: s3Region,
|
|
||||||
credentials: {
|
|
||||||
accessKeyId: s3AccessKey,
|
|
||||||
secretAccessKey: s3SecretKey,
|
|
||||||
},
|
|
||||||
forcePathStyle: false, // Hetzner uses virtual-hosted style
|
|
||||||
});
|
|
||||||
this.logger.log(`Storage initialized in S3 mode (endpoint: ${s3Endpoint})`);
|
|
||||||
} else {
|
|
||||||
this.logger.warn('S3 credentials not configured, falling back to local storage');
|
|
||||||
this.mode = 'local';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.mode === 'local') {
|
|
||||||
this.logger.log(`Storage initialized in local mode (path: ${this.localStoragePath})`);
|
|
||||||
this.ensureLocalStorageDirectory();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async ensureLocalStorageDirectory(): Promise<void> {
|
onModuleInit() {
|
||||||
try {
|
// Initialize storage client
|
||||||
await fs.mkdir(this.localStoragePath, { recursive: true });
|
this.storage = createPictureStorage(this.publicUrl);
|
||||||
} catch (error) {
|
this.logger.log(`Storage initialized with @manacore/shared-storage (bucket: picture-storage)`);
|
||||||
this.logger.error('Failed to create local storage directory', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async uploadFile(
|
async uploadFile(
|
||||||
|
|
@ -88,59 +40,16 @@ export class StorageService {
|
||||||
const ext = filename.split('.').pop() || 'jpg';
|
const ext = filename.split('.').pop() || 'jpg';
|
||||||
const storagePath = `${userId}/${timestamp}-${randomId}.${ext}`;
|
const storagePath = `${userId}/${timestamp}-${randomId}.${ext}`;
|
||||||
|
|
||||||
if (this.mode === 's3' && this.s3Client) {
|
const result = await this.storage.upload(storagePath, buffer, {
|
||||||
return this.uploadToS3(buffer, storagePath, contentType);
|
contentType,
|
||||||
} else {
|
public: true,
|
||||||
return this.uploadToLocal(buffer, storagePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async uploadToS3(
|
|
||||||
buffer: Buffer,
|
|
||||||
storagePath: string,
|
|
||||||
contentType: string
|
|
||||||
): Promise<{ storagePath: string; publicUrl: string }> {
|
|
||||||
if (!this.s3Client) {
|
|
||||||
throw new Error('S3 client not configured');
|
|
||||||
}
|
|
||||||
|
|
||||||
const command = new PutObjectCommand({
|
|
||||||
Bucket: this.bucket,
|
|
||||||
Key: storagePath,
|
|
||||||
Body: buffer,
|
|
||||||
ContentType: contentType,
|
|
||||||
ACL: 'public-read',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
const publicUrl = result.url || this.getPublicUrl(storagePath);
|
||||||
await this.s3Client.send(command);
|
|
||||||
const publicUrl = `${this.publicUrlBase}/${storagePath}`;
|
|
||||||
|
|
||||||
return { storagePath, publicUrl };
|
this.logger.debug(`Uploaded file to ${storagePath}`);
|
||||||
} catch (error) {
|
|
||||||
this.logger.error('Error uploading file to S3', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async uploadToLocal(
|
return { storagePath, publicUrl };
|
||||||
buffer: Buffer,
|
|
||||||
storagePath: string
|
|
||||||
): Promise<{ storagePath: string; publicUrl: string }> {
|
|
||||||
const fullPath = path.join(this.localStoragePath, storagePath);
|
|
||||||
const directory = path.dirname(fullPath);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await fs.mkdir(directory, { recursive: true });
|
|
||||||
await fs.writeFile(fullPath, buffer);
|
|
||||||
|
|
||||||
const publicUrl = `${this.publicUrlBase}/${storagePath}`;
|
|
||||||
|
|
||||||
return { storagePath, publicUrl };
|
|
||||||
} catch (error) {
|
|
||||||
this.logger.error('Error uploading file to local storage', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async uploadFromUrl(
|
async uploadFromUrl(
|
||||||
|
|
@ -161,109 +70,42 @@ export class StorageService {
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteFile(storagePath: string): Promise<void> {
|
async deleteFile(storagePath: string): Promise<void> {
|
||||||
if (this.mode === 's3' && this.s3Client) {
|
|
||||||
return this.deleteFromS3(storagePath);
|
|
||||||
} else {
|
|
||||||
return this.deleteFromLocal(storagePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async deleteFromS3(storagePath: string): Promise<void> {
|
|
||||||
if (!this.s3Client) {
|
|
||||||
throw new Error('S3 client not configured');
|
|
||||||
}
|
|
||||||
|
|
||||||
const command = new DeleteObjectCommand({
|
|
||||||
Bucket: this.bucket,
|
|
||||||
Key: storagePath,
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.s3Client.send(command);
|
await this.storage.delete(storagePath);
|
||||||
|
this.logger.debug(`Deleted file: ${storagePath}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(`Error deleting file ${storagePath} from S3`, error);
|
this.logger.error(`Error deleting file ${storagePath}`, error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async deleteFromLocal(storagePath: string): Promise<void> {
|
|
||||||
const fullPath = path.join(this.localStoragePath, storagePath);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await fs.unlink(fullPath);
|
|
||||||
} catch (error) {
|
|
||||||
// Ignore if file doesn't exist
|
|
||||||
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
|
||||||
this.logger.error(`Error deleting file ${storagePath} from local storage`, error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async uploadBoardThumbnail(boardId: string, dataUrl: string): Promise<string> {
|
async uploadBoardThumbnail(boardId: string, dataUrl: string): Promise<string> {
|
||||||
const base64Data = dataUrl.replace(/^data:image\/\w+;base64,/, '');
|
const base64Data = dataUrl.replace(/^data:image\/\w+;base64,/, '');
|
||||||
const buffer = Buffer.from(base64Data, 'base64');
|
const buffer = Buffer.from(base64Data, 'base64');
|
||||||
const storagePath = `boards/${boardId}/thumbnail-${Date.now()}.png`;
|
const storagePath = `boards/${boardId}/thumbnail-${Date.now()}.png`;
|
||||||
|
|
||||||
if (this.mode === 's3' && this.s3Client) {
|
const result = await this.storage.upload(storagePath, buffer, {
|
||||||
const result = await this.uploadToS3(buffer, storagePath, 'image/png');
|
contentType: 'image/png',
|
||||||
return result.publicUrl;
|
public: true,
|
||||||
} else {
|
});
|
||||||
const result = await this.uploadToLocal(buffer, storagePath);
|
|
||||||
return result.publicUrl;
|
return result.url || this.getPublicUrl(storagePath);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFile(storagePath: string): Promise<Buffer | null> {
|
async getFile(storagePath: string): Promise<Buffer | null> {
|
||||||
if (this.mode === 's3' && this.s3Client) {
|
|
||||||
return this.getFromS3(storagePath);
|
|
||||||
} else {
|
|
||||||
return this.getFromLocal(storagePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getFromS3(storagePath: string): Promise<Buffer | null> {
|
|
||||||
if (!this.s3Client) {
|
|
||||||
throw new Error('S3 client not configured');
|
|
||||||
}
|
|
||||||
|
|
||||||
const command = new GetObjectCommand({
|
|
||||||
Bucket: this.bucket,
|
|
||||||
Key: storagePath,
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await this.s3Client.send(command);
|
return await this.storage.download(storagePath);
|
||||||
if (response.Body) {
|
|
||||||
const byteArray = await response.Body.transformToByteArray();
|
|
||||||
return Buffer.from(byteArray);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(`Error getting file ${storagePath} from S3`, error);
|
this.logger.error(`Error getting file ${storagePath}`, error);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getFromLocal(storagePath: string): Promise<Buffer | null> {
|
|
||||||
const fullPath = path.join(this.localStoragePath, storagePath);
|
|
||||||
|
|
||||||
try {
|
|
||||||
return await fs.readFile(fullPath);
|
|
||||||
} catch (error) {
|
|
||||||
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
this.logger.error(`Error getting file ${storagePath} from local storage`, error);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getStorageMode(): StorageMode {
|
getStorageMode(): StorageMode {
|
||||||
return this.mode;
|
return 's3';
|
||||||
}
|
}
|
||||||
|
|
||||||
getPublicUrl(storagePath: string): string {
|
getPublicUrl(storagePath: string): string {
|
||||||
return `${this.publicUrlBase}/${storagePath}`;
|
return this.storage.getPublicUrl(storagePath) || `${this.publicUrl}/${storagePath}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
505
pnpm-lock.yaml
generated
505
pnpm-lock.yaml
generated
|
|
@ -116,7 +116,7 @@ importers:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@nestjs/cli':
|
'@nestjs/cli':
|
||||||
specifier: ^10.4.9
|
specifier: ^10.4.9
|
||||||
version: 10.4.9(esbuild@0.19.12)
|
version: 10.4.9(esbuild@0.27.0)
|
||||||
'@nestjs/schematics':
|
'@nestjs/schematics':
|
||||||
specifier: ^10.2.3
|
specifier: ^10.2.3
|
||||||
version: 10.2.3(chokidar@3.6.0)(typescript@5.9.3)
|
version: 10.2.3(chokidar@3.6.0)(typescript@5.9.3)
|
||||||
|
|
@ -149,7 +149,7 @@ importers:
|
||||||
version: 0.5.21
|
version: 0.5.21
|
||||||
ts-loader:
|
ts-loader:
|
||||||
specifier: ^9.5.1
|
specifier: ^9.5.1
|
||||||
version: 9.5.4(typescript@5.9.3)(webpack@5.97.1(esbuild@0.19.12))
|
version: 9.5.4(typescript@5.9.3)(webpack@5.100.2(esbuild@0.27.0))
|
||||||
ts-node:
|
ts-node:
|
||||||
specifier: ^10.9.2
|
specifier: ^10.9.2
|
||||||
version: 10.9.2(@types/node@22.19.1)(typescript@5.9.3)
|
version: 10.9.2(@types/node@22.19.1)(typescript@5.9.3)
|
||||||
|
|
@ -173,14 +173,14 @@ importers:
|
||||||
version: link:../../../../packages/shared-landing-ui
|
version: link:../../../../packages/shared-landing-ui
|
||||||
astro:
|
astro:
|
||||||
specifier: ^5.16.0
|
specifier: ^5.16.0
|
||||||
version: 5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)
|
version: 5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^5.9.2
|
specifier: ^5.9.2
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@astrojs/tailwind':
|
'@astrojs/tailwind':
|
||||||
specifier: ^6.0.2
|
specifier: ^6.0.2
|
||||||
version: 6.0.2(astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3))
|
version: 6.0.2(astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3))
|
||||||
'@tailwindcss/typography':
|
'@tailwindcss/typography':
|
||||||
specifier: ^0.5.18
|
specifier: ^0.5.18
|
||||||
version: 0.5.19(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))
|
version: 0.5.19(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))
|
||||||
|
|
@ -189,13 +189,13 @@ importers:
|
||||||
version: 20.19.25
|
version: 20.19.25
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^9.0.0
|
specifier: ^9.0.0
|
||||||
version: 9.39.1(jiti@1.21.7)
|
version: 9.39.1(jiti@2.6.1)
|
||||||
eslint-config-prettier:
|
eslint-config-prettier:
|
||||||
specifier: ^9.1.0
|
specifier: ^9.1.0
|
||||||
version: 9.1.2(eslint@9.39.1(jiti@1.21.7))
|
version: 9.1.2(eslint@9.39.1(jiti@2.6.1))
|
||||||
eslint-plugin-astro:
|
eslint-plugin-astro:
|
||||||
specifier: ^1.0.0
|
specifier: ^1.0.0
|
||||||
version: 1.5.0(eslint@9.39.1(jiti@1.21.7))
|
version: 1.5.0(eslint@9.39.1(jiti@2.6.1))
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^3.6.2
|
specifier: ^3.6.2
|
||||||
version: 3.6.2
|
version: 3.6.2
|
||||||
|
|
@ -537,19 +537,19 @@ importers:
|
||||||
version: 18.3.27
|
version: 18.3.27
|
||||||
'@typescript-eslint/eslint-plugin':
|
'@typescript-eslint/eslint-plugin':
|
||||||
specifier: ^7.7.0
|
specifier: ^7.7.0
|
||||||
version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)
|
version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)
|
||||||
'@typescript-eslint/parser':
|
'@typescript-eslint/parser':
|
||||||
specifier: ^7.7.0
|
specifier: ^7.7.0
|
||||||
version: 7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)
|
version: 7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)
|
||||||
dotenv:
|
dotenv:
|
||||||
specifier: ^16.4.7
|
specifier: ^16.4.7
|
||||||
version: 16.6.1
|
version: 16.6.1
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^9.39.1
|
specifier: ^9.39.1
|
||||||
version: 9.39.1(jiti@2.6.1)
|
version: 9.39.1(jiti@1.21.7)
|
||||||
eslint-config-universe:
|
eslint-config-universe:
|
||||||
specifier: ^12.0.1
|
specifier: ^12.0.1
|
||||||
version: 12.1.0(@types/eslint@9.6.1)(eslint@9.39.1(jiti@2.6.1))(prettier@3.6.2)(typescript@5.3.3)
|
version: 12.1.0(@types/eslint@9.6.1)(eslint@9.39.1(jiti@1.21.7))(prettier@3.6.2)(typescript@5.3.3)
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^3.2.5
|
specifier: ^3.2.5
|
||||||
version: 3.6.2
|
version: 3.6.2
|
||||||
|
|
@ -2012,12 +2012,18 @@ importers:
|
||||||
'@aws-sdk/client-s3':
|
'@aws-sdk/client-s3':
|
||||||
specifier: ^3.700.0
|
specifier: ^3.700.0
|
||||||
version: 3.940.0
|
version: 3.940.0
|
||||||
|
'@mana-core/nestjs-integration':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../../../../packages/mana-core-nestjs-integration
|
||||||
'@manacore/shared-errors':
|
'@manacore/shared-errors':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../../../packages/shared-errors
|
version: link:../../../../packages/shared-errors
|
||||||
'@manacore/shared-nestjs-auth':
|
'@manacore/shared-nestjs-auth':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../../../packages/shared-nestjs-auth
|
version: link:../../../../packages/shared-nestjs-auth
|
||||||
|
'@manacore/shared-storage':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../../../../packages/shared-storage
|
||||||
'@nestjs/common':
|
'@nestjs/common':
|
||||||
specifier: ^10.4.15
|
specifier: ^10.4.15
|
||||||
version: 10.4.20(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
version: 10.4.20(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||||
|
|
@ -2066,7 +2072,7 @@ importers:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@nestjs/cli':
|
'@nestjs/cli':
|
||||||
specifier: ^10.4.9
|
specifier: ^10.4.9
|
||||||
version: 10.4.9(esbuild@0.27.0)
|
version: 10.4.9(esbuild@0.19.12)
|
||||||
'@nestjs/schematics':
|
'@nestjs/schematics':
|
||||||
specifier: ^10.2.3
|
specifier: ^10.2.3
|
||||||
version: 10.2.3(chokidar@3.6.0)(typescript@5.9.3)
|
version: 10.2.3(chokidar@3.6.0)(typescript@5.9.3)
|
||||||
|
|
@ -2102,7 +2108,7 @@ importers:
|
||||||
version: 0.5.21
|
version: 0.5.21
|
||||||
ts-loader:
|
ts-loader:
|
||||||
specifier: ^9.5.1
|
specifier: ^9.5.1
|
||||||
version: 9.5.4(typescript@5.9.3)(webpack@5.100.2(esbuild@0.27.0))
|
version: 9.5.4(typescript@5.9.3)(webpack@5.97.1(esbuild@0.19.12))
|
||||||
ts-node:
|
ts-node:
|
||||||
specifier: ^10.9.2
|
specifier: ^10.9.2
|
||||||
version: 10.9.2(@types/node@22.19.1)(typescript@5.9.3)
|
version: 10.9.2(@types/node@22.19.1)(typescript@5.9.3)
|
||||||
|
|
@ -6712,7 +6718,7 @@ packages:
|
||||||
|
|
||||||
'@expo/bunyan@4.0.1':
|
'@expo/bunyan@4.0.1':
|
||||||
resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==}
|
resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==}
|
||||||
engines: {'0': node >=0.10.0}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
'@expo/cli@0.22.26':
|
'@expo/cli@0.22.26':
|
||||||
resolution: {integrity: sha512-I689wc8Fn/AX7aUGiwrh3HnssiORMJtR2fpksX+JIe8Cj/EDleblYMSwRPd0025wrwOV9UN1KM/RuEt/QjCS3Q==}
|
resolution: {integrity: sha512-I689wc8Fn/AX7aUGiwrh3HnssiORMJtR2fpksX+JIe8Cj/EDleblYMSwRPd0025wrwOV9UN1KM/RuEt/QjCS3Q==}
|
||||||
|
|
@ -19888,16 +19894,6 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- ts-node
|
- ts-node
|
||||||
|
|
||||||
'@astrojs/tailwind@6.0.2(astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3))':
|
|
||||||
dependencies:
|
|
||||||
astro: 5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)
|
|
||||||
autoprefixer: 10.4.22(postcss@8.5.6)
|
|
||||||
postcss: 8.5.6
|
|
||||||
postcss-load-config: 4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3))
|
|
||||||
tailwindcss: 3.4.18(tsx@4.20.6)(yaml@2.8.1)
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- ts-node
|
|
||||||
|
|
||||||
'@astrojs/tailwind@6.0.2(astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3))':
|
'@astrojs/tailwind@6.0.2(astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(tailwindcss@3.4.18(tsx@4.20.6)(yaml@2.8.1))(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
astro: 5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)
|
astro: 5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1)
|
||||||
|
|
@ -22411,7 +22407,7 @@ snapshots:
|
||||||
wrap-ansi: 7.0.0
|
wrap-ansi: 7.0.0
|
||||||
ws: 8.18.3
|
ws: 8.18.3
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
expo-router: 6.0.15(5e7ih2rh6mb55wruwvjljgzihq)
|
expo-router: 6.0.15(jiucxy5ca3jdtbnulaxuc46jdq)
|
||||||
react-native: 0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0)
|
react-native: 0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@modelcontextprotocol/sdk'
|
- '@modelcontextprotocol/sdk'
|
||||||
|
|
@ -27278,6 +27274,19 @@ snapshots:
|
||||||
react-test-renderer: 19.1.0(react@19.1.0)
|
react-test-renderer: 19.1.0(react@19.1.0)
|
||||||
redent: 3.0.0
|
redent: 3.0.0
|
||||||
|
|
||||||
|
'@testing-library/react-native@13.3.3(jest@30.2.0(@types/node@20.19.25)(esbuild-register@3.6.0(esbuild@0.27.0)))(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react-test-renderer@19.1.0(react@19.1.0))(react@19.1.0)':
|
||||||
|
dependencies:
|
||||||
|
jest-matcher-utils: 30.2.0
|
||||||
|
picocolors: 1.1.1
|
||||||
|
pretty-format: 30.2.0
|
||||||
|
react: 19.1.0
|
||||||
|
react-native: 0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0)
|
||||||
|
react-test-renderer: 19.1.0(react@19.1.0)
|
||||||
|
redent: 3.0.0
|
||||||
|
optionalDependencies:
|
||||||
|
jest: 30.2.0(@types/node@20.19.25)(esbuild-register@3.6.0(esbuild@0.27.0))
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@testing-library/react-native@13.3.3(jest@30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react-test-renderer@19.1.0(react@19.1.0))(react@19.1.0)':
|
'@testing-library/react-native@13.3.3(jest@30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react-test-renderer@19.1.0(react@19.1.0))(react@19.1.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
jest-matcher-utils: 30.2.0
|
jest-matcher-utils: 30.2.0
|
||||||
|
|
@ -27820,16 +27829,16 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)':
|
'@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint-community/regexpp': 4.12.2
|
'@eslint-community/regexpp': 4.12.2
|
||||||
'@typescript-eslint/parser': 6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)
|
'@typescript-eslint/parser': 6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)
|
||||||
'@typescript-eslint/scope-manager': 6.21.0
|
'@typescript-eslint/scope-manager': 6.21.0
|
||||||
'@typescript-eslint/type-utils': 6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)
|
'@typescript-eslint/type-utils': 6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)
|
||||||
'@typescript-eslint/utils': 6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)
|
'@typescript-eslint/utils': 6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)
|
||||||
'@typescript-eslint/visitor-keys': 6.21.0
|
'@typescript-eslint/visitor-keys': 6.21.0
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@1.21.7)
|
||||||
graphemer: 1.4.0
|
graphemer: 1.4.0
|
||||||
ignore: 5.3.2
|
ignore: 5.3.2
|
||||||
natural-compare: 1.4.0
|
natural-compare: 1.4.0
|
||||||
|
|
@ -27878,15 +27887,15 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)':
|
'@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint-community/regexpp': 4.12.2
|
'@eslint-community/regexpp': 4.12.2
|
||||||
'@typescript-eslint/parser': 7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)
|
'@typescript-eslint/parser': 7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)
|
||||||
'@typescript-eslint/scope-manager': 7.18.0
|
'@typescript-eslint/scope-manager': 7.18.0
|
||||||
'@typescript-eslint/type-utils': 7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)
|
'@typescript-eslint/type-utils': 7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)
|
||||||
'@typescript-eslint/utils': 7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)
|
'@typescript-eslint/utils': 7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)
|
||||||
'@typescript-eslint/visitor-keys': 7.18.0
|
'@typescript-eslint/visitor-keys': 7.18.0
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@1.21.7)
|
||||||
graphemer: 1.4.0
|
graphemer: 1.4.0
|
||||||
ignore: 5.3.2
|
ignore: 5.3.2
|
||||||
natural-compare: 1.4.0
|
natural-compare: 1.4.0
|
||||||
|
|
@ -27978,14 +27987,14 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)':
|
'@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/scope-manager': 6.21.0
|
'@typescript-eslint/scope-manager': 6.21.0
|
||||||
'@typescript-eslint/types': 6.21.0
|
'@typescript-eslint/types': 6.21.0
|
||||||
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3)
|
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3)
|
||||||
'@typescript-eslint/visitor-keys': 6.21.0
|
'@typescript-eslint/visitor-keys': 6.21.0
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@1.21.7)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.3.3
|
typescript: 5.3.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
|
@ -28017,14 +28026,14 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)':
|
'@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/scope-manager': 7.18.0
|
'@typescript-eslint/scope-manager': 7.18.0
|
||||||
'@typescript-eslint/types': 7.18.0
|
'@typescript-eslint/types': 7.18.0
|
||||||
'@typescript-eslint/typescript-estree': 7.18.0(typescript@5.3.3)
|
'@typescript-eslint/typescript-estree': 7.18.0(typescript@5.3.3)
|
||||||
'@typescript-eslint/visitor-keys': 7.18.0
|
'@typescript-eslint/visitor-keys': 7.18.0
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@1.21.7)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.3.3
|
typescript: 5.3.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
|
@ -28150,12 +28159,12 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@typescript-eslint/type-utils@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)':
|
'@typescript-eslint/type-utils@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3)
|
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3)
|
||||||
'@typescript-eslint/utils': 6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)
|
'@typescript-eslint/utils': 6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@1.21.7)
|
||||||
ts-api-utils: 1.4.3(typescript@5.3.3)
|
ts-api-utils: 1.4.3(typescript@5.3.3)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.3.3
|
typescript: 5.3.3
|
||||||
|
|
@ -28186,12 +28195,12 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@typescript-eslint/type-utils@7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)':
|
'@typescript-eslint/type-utils@7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/typescript-estree': 7.18.0(typescript@5.3.3)
|
'@typescript-eslint/typescript-estree': 7.18.0(typescript@5.3.3)
|
||||||
'@typescript-eslint/utils': 7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)
|
'@typescript-eslint/utils': 7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@1.21.7)
|
||||||
ts-api-utils: 1.4.3(typescript@5.3.3)
|
ts-api-utils: 1.4.3(typescript@5.3.3)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.3.3
|
typescript: 5.3.3
|
||||||
|
|
@ -28373,15 +28382,15 @@ snapshots:
|
||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
'@typescript-eslint/utils@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)':
|
'@typescript-eslint/utils@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1))
|
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@1.21.7))
|
||||||
'@types/json-schema': 7.0.15
|
'@types/json-schema': 7.0.15
|
||||||
'@types/semver': 7.7.1
|
'@types/semver': 7.7.1
|
||||||
'@typescript-eslint/scope-manager': 6.21.0
|
'@typescript-eslint/scope-manager': 6.21.0
|
||||||
'@typescript-eslint/types': 6.21.0
|
'@typescript-eslint/types': 6.21.0
|
||||||
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3)
|
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3)
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@1.21.7)
|
||||||
semver: 7.7.3
|
semver: 7.7.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
@ -28412,13 +28421,13 @@ snapshots:
|
||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
'@typescript-eslint/utils@7.18.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)':
|
'@typescript-eslint/utils@7.18.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1))
|
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@1.21.7))
|
||||||
'@typescript-eslint/scope-manager': 7.18.0
|
'@typescript-eslint/scope-manager': 7.18.0
|
||||||
'@typescript-eslint/types': 7.18.0
|
'@typescript-eslint/types': 7.18.0
|
||||||
'@typescript-eslint/typescript-estree': 7.18.0(typescript@5.3.3)
|
'@typescript-eslint/typescript-estree': 7.18.0(typescript@5.3.3)
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@1.21.7)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- typescript
|
||||||
|
|
@ -29219,108 +29228,6 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@1.21.7)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1):
|
|
||||||
dependencies:
|
|
||||||
'@astrojs/compiler': 2.13.0
|
|
||||||
'@astrojs/internal-helpers': 0.7.5
|
|
||||||
'@astrojs/markdown-remark': 6.3.9
|
|
||||||
'@astrojs/telemetry': 3.3.0
|
|
||||||
'@capsizecss/unpack': 3.0.1
|
|
||||||
'@oslojs/encoding': 1.1.0
|
|
||||||
'@rollup/pluginutils': 5.3.0(rollup@4.53.3)
|
|
||||||
acorn: 8.15.0
|
|
||||||
aria-query: 5.3.2
|
|
||||||
axobject-query: 4.1.0
|
|
||||||
boxen: 8.0.1
|
|
||||||
ci-info: 4.3.1
|
|
||||||
clsx: 2.1.1
|
|
||||||
common-ancestor-path: 1.0.1
|
|
||||||
cookie: 1.1.0
|
|
||||||
cssesc: 3.0.0
|
|
||||||
debug: 4.4.3
|
|
||||||
deterministic-object-hash: 2.0.2
|
|
||||||
devalue: 5.5.0
|
|
||||||
diff: 5.2.0
|
|
||||||
dlv: 1.1.3
|
|
||||||
dset: 3.1.4
|
|
||||||
es-module-lexer: 1.7.0
|
|
||||||
esbuild: 0.25.12
|
|
||||||
estree-walker: 3.0.3
|
|
||||||
flattie: 1.1.1
|
|
||||||
fontace: 0.3.1
|
|
||||||
github-slugger: 2.0.0
|
|
||||||
html-escaper: 3.0.3
|
|
||||||
http-cache-semantics: 4.2.0
|
|
||||||
import-meta-resolve: 4.2.0
|
|
||||||
js-yaml: 4.1.1
|
|
||||||
magic-string: 0.30.21
|
|
||||||
magicast: 0.5.1
|
|
||||||
mrmime: 2.0.1
|
|
||||||
neotraverse: 0.6.18
|
|
||||||
p-limit: 6.2.0
|
|
||||||
p-queue: 8.1.1
|
|
||||||
package-manager-detector: 1.5.0
|
|
||||||
piccolore: 0.1.3
|
|
||||||
picomatch: 4.0.3
|
|
||||||
prompts: 2.4.2
|
|
||||||
rehype: 13.0.2
|
|
||||||
semver: 7.7.3
|
|
||||||
shiki: 3.15.0
|
|
||||||
smol-toml: 1.5.2
|
|
||||||
svgo: 4.0.0
|
|
||||||
tinyexec: 1.0.2
|
|
||||||
tinyglobby: 0.2.15
|
|
||||||
tsconfck: 3.1.6(typescript@5.9.3)
|
|
||||||
ultrahtml: 1.6.0
|
|
||||||
unifont: 0.6.0
|
|
||||||
unist-util-visit: 5.0.0
|
|
||||||
unstorage: 1.17.3(@netlify/blobs@10.4.1)(ioredis@5.8.2)
|
|
||||||
vfile: 6.0.3
|
|
||||||
vite: 6.4.1(@types/node@20.19.25)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)
|
|
||||||
vitefu: 1.1.1(vite@6.4.1(@types/node@20.19.25)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))
|
|
||||||
xxhash-wasm: 1.1.0
|
|
||||||
yargs-parser: 21.1.1
|
|
||||||
yocto-spinner: 0.2.3
|
|
||||||
zod: 3.25.76
|
|
||||||
zod-to-json-schema: 3.25.0(zod@3.25.76)
|
|
||||||
zod-to-ts: 1.2.0(typescript@5.9.3)(zod@3.25.76)
|
|
||||||
optionalDependencies:
|
|
||||||
sharp: 0.34.5
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- '@azure/app-configuration'
|
|
||||||
- '@azure/cosmos'
|
|
||||||
- '@azure/data-tables'
|
|
||||||
- '@azure/identity'
|
|
||||||
- '@azure/keyvault-secrets'
|
|
||||||
- '@azure/storage-blob'
|
|
||||||
- '@capacitor/preferences'
|
|
||||||
- '@deno/kv'
|
|
||||||
- '@netlify/blobs'
|
|
||||||
- '@planetscale/database'
|
|
||||||
- '@types/node'
|
|
||||||
- '@upstash/redis'
|
|
||||||
- '@vercel/blob'
|
|
||||||
- '@vercel/functions'
|
|
||||||
- '@vercel/kv'
|
|
||||||
- aws4fetch
|
|
||||||
- db0
|
|
||||||
- idb-keyval
|
|
||||||
- ioredis
|
|
||||||
- jiti
|
|
||||||
- less
|
|
||||||
- lightningcss
|
|
||||||
- rollup
|
|
||||||
- sass
|
|
||||||
- sass-embedded
|
|
||||||
- stylus
|
|
||||||
- sugarss
|
|
||||||
- supports-color
|
|
||||||
- terser
|
|
||||||
- tsx
|
|
||||||
- typescript
|
|
||||||
- uploadthing
|
|
||||||
- yaml
|
|
||||||
|
|
||||||
astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1):
|
astro@5.16.0(@netlify/blobs@10.4.1)(@types/node@20.19.25)(ioredis@5.8.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.53.3)(terser@5.44.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@astrojs/compiler': 2.13.0
|
'@astrojs/compiler': 2.13.0
|
||||||
|
|
@ -31606,11 +31513,6 @@ snapshots:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
source-map: 0.6.1
|
source-map: 0.6.1
|
||||||
|
|
||||||
eslint-compat-utils@0.6.5(eslint@9.39.1(jiti@1.21.7)):
|
|
||||||
dependencies:
|
|
||||||
eslint: 9.39.1(jiti@1.21.7)
|
|
||||||
semver: 7.7.3
|
|
||||||
|
|
||||||
eslint-compat-utils@0.6.5(eslint@9.39.1(jiti@2.6.1)):
|
eslint-compat-utils@0.6.5(eslint@9.39.1(jiti@2.6.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@2.6.1)
|
||||||
|
|
@ -31621,9 +31523,9 @@ snapshots:
|
||||||
'@typescript-eslint/eslint-plugin': 8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
|
'@typescript-eslint/eslint-plugin': 8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
|
||||||
'@typescript-eslint/parser': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
|
'@typescript-eslint/parser': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@2.6.1)
|
||||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))
|
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1))
|
||||||
eslint-plugin-expo: 1.0.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
|
eslint-plugin-expo: 1.0.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
|
||||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1))
|
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))
|
||||||
eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@2.6.1))
|
eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@2.6.1))
|
||||||
eslint-plugin-react-hooks: 5.2.0(eslint@9.39.1(jiti@2.6.1))
|
eslint-plugin-react-hooks: 5.2.0(eslint@9.39.1(jiti@2.6.1))
|
||||||
globals: 16.5.0
|
globals: 16.5.0
|
||||||
|
|
@ -31638,9 +31540,9 @@ snapshots:
|
||||||
'@typescript-eslint/eslint-plugin': 8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3)
|
'@typescript-eslint/eslint-plugin': 8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3)
|
||||||
'@typescript-eslint/parser': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3)
|
'@typescript-eslint/parser': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3)
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@2.6.1)
|
||||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))
|
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1))
|
||||||
eslint-plugin-expo: 0.1.4(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3)
|
eslint-plugin-expo: 0.1.4(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3)
|
||||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1))
|
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.1(jiti@2.6.1))
|
||||||
eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@2.6.1))
|
eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@2.6.1))
|
||||||
eslint-plugin-react-hooks: 5.2.0(eslint@9.39.1(jiti@2.6.1))
|
eslint-plugin-react-hooks: 5.2.0(eslint@9.39.1(jiti@2.6.1))
|
||||||
globals: 16.5.0
|
globals: 16.5.0
|
||||||
|
|
@ -31658,14 +31560,14 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 8.57.1
|
eslint: 8.57.1
|
||||||
|
|
||||||
|
eslint-config-prettier@8.10.2(eslint@9.39.1(jiti@1.21.7)):
|
||||||
|
dependencies:
|
||||||
|
eslint: 9.39.1(jiti@1.21.7)
|
||||||
|
|
||||||
eslint-config-prettier@8.10.2(eslint@9.39.1(jiti@2.6.1)):
|
eslint-config-prettier@8.10.2(eslint@9.39.1(jiti@2.6.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@2.6.1)
|
||||||
|
|
||||||
eslint-config-prettier@9.1.2(eslint@9.39.1(jiti@1.21.7)):
|
|
||||||
dependencies:
|
|
||||||
eslint: 9.39.1(jiti@1.21.7)
|
|
||||||
|
|
||||||
eslint-config-prettier@9.1.2(eslint@9.39.1(jiti@2.6.1)):
|
eslint-config-prettier@9.1.2(eslint@9.39.1(jiti@2.6.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@2.6.1)
|
||||||
|
|
@ -31690,17 +31592,17 @@ snapshots:
|
||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
eslint-config-universe@12.1.0(@types/eslint@9.6.1)(eslint@9.39.1(jiti@2.6.1))(prettier@3.6.2)(typescript@5.3.3):
|
eslint-config-universe@12.1.0(@types/eslint@9.6.1)(eslint@9.39.1(jiti@1.21.7))(prettier@3.6.2)(typescript@5.3.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)
|
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)
|
||||||
'@typescript-eslint/parser': 6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)
|
'@typescript-eslint/parser': 6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@1.21.7)
|
||||||
eslint-config-prettier: 8.10.2(eslint@9.39.1(jiti@2.6.1))
|
eslint-config-prettier: 8.10.2(eslint@9.39.1(jiti@1.21.7))
|
||||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3))(eslint@9.39.1(jiti@2.6.1))
|
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3))(eslint@9.39.1(jiti@1.21.7))
|
||||||
eslint-plugin-node: 11.1.0(eslint@9.39.1(jiti@2.6.1))
|
eslint-plugin-node: 11.1.0(eslint@9.39.1(jiti@1.21.7))
|
||||||
eslint-plugin-prettier: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@8.10.2(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))(prettier@3.6.2)
|
eslint-plugin-prettier: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@8.10.2(eslint@9.39.1(jiti@1.21.7)))(eslint@9.39.1(jiti@1.21.7))(prettier@3.6.2)
|
||||||
eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@2.6.1))
|
eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@1.21.7))
|
||||||
eslint-plugin-react-hooks: 4.6.2(eslint@9.39.1(jiti@2.6.1))
|
eslint-plugin-react-hooks: 4.6.2(eslint@9.39.1(jiti@1.21.7))
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
prettier: 3.6.2
|
prettier: 3.6.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
|
@ -31738,7 +31640,7 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)):
|
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nolyfill/is-core-module': 1.0.39
|
'@nolyfill/is-core-module': 1.0.39
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
|
|
@ -31749,22 +31651,7 @@ snapshots:
|
||||||
tinyglobby: 0.2.15
|
tinyglobby: 0.2.15
|
||||||
unrs-resolver: 1.11.1
|
unrs-resolver: 1.11.1
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1))
|
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
|
|
||||||
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)):
|
|
||||||
dependencies:
|
|
||||||
'@nolyfill/is-core-module': 1.0.39
|
|
||||||
debug: 4.4.3
|
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
|
||||||
get-tsconfig: 4.13.0
|
|
||||||
is-bun-module: 2.0.0
|
|
||||||
stable-hash: 0.0.5
|
|
||||||
tinyglobby: 0.2.15
|
|
||||||
unrs-resolver: 1.11.1
|
|
||||||
optionalDependencies:
|
|
||||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1))
|
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
|
@ -31778,12 +31665,12 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
eslint-module-utils@2.12.1(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1)):
|
eslint-module-utils@2.12.1(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@1.21.7)):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 3.2.7
|
debug: 3.2.7
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@typescript-eslint/parser': 6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)
|
'@typescript-eslint/parser': 6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@1.21.7)
|
||||||
eslint-import-resolver-node: 0.3.9
|
eslint-import-resolver-node: 0.3.9
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
@ -31798,39 +31685,25 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)):
|
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 3.2.7
|
debug: 3.2.7
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@typescript-eslint/parser': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3)
|
'@typescript-eslint/parser': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3)
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@2.6.1)
|
||||||
eslint-import-resolver-node: 0.3.9
|
eslint-import-resolver-node: 0.3.9
|
||||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))
|
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1))
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)):
|
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 3.2.7
|
debug: 3.2.7
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@typescript-eslint/parser': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
|
'@typescript-eslint/parser': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@2.6.1)
|
||||||
eslint-import-resolver-node: 0.3.9
|
eslint-import-resolver-node: 0.3.9
|
||||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))
|
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1))
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
|
|
||||||
eslint-plugin-astro@1.5.0(eslint@9.39.1(jiti@1.21.7)):
|
|
||||||
dependencies:
|
|
||||||
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@1.21.7))
|
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
|
||||||
'@typescript-eslint/types': 8.48.0
|
|
||||||
astro-eslint-parser: 1.2.2
|
|
||||||
eslint: 9.39.1(jiti@1.21.7)
|
|
||||||
eslint-compat-utils: 0.6.5(eslint@9.39.1(jiti@1.21.7))
|
|
||||||
globals: 16.5.0
|
|
||||||
postcss: 8.5.6
|
|
||||||
postcss-selector-parser: 7.1.0
|
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
|
@ -31854,6 +31727,12 @@ snapshots:
|
||||||
eslint-utils: 2.1.0
|
eslint-utils: 2.1.0
|
||||||
regexpp: 3.2.0
|
regexpp: 3.2.0
|
||||||
|
|
||||||
|
eslint-plugin-es@3.0.1(eslint@9.39.1(jiti@1.21.7)):
|
||||||
|
dependencies:
|
||||||
|
eslint: 9.39.1(jiti@1.21.7)
|
||||||
|
eslint-utils: 2.1.0
|
||||||
|
regexpp: 3.2.0
|
||||||
|
|
||||||
eslint-plugin-es@3.0.1(eslint@9.39.1(jiti@2.6.1)):
|
eslint-plugin-es@3.0.1(eslint@9.39.1(jiti@2.6.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@2.6.1)
|
||||||
|
|
@ -31907,7 +31786,7 @@ snapshots:
|
||||||
- eslint-import-resolver-webpack
|
- eslint-import-resolver-webpack
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3))(eslint@9.39.1(jiti@2.6.1)):
|
eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3))(eslint@9.39.1(jiti@1.21.7)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rtsao/scc': 1.1.0
|
'@rtsao/scc': 1.1.0
|
||||||
array-includes: 3.1.9
|
array-includes: 3.1.9
|
||||||
|
|
@ -31916,9 +31795,9 @@ snapshots:
|
||||||
array.prototype.flatmap: 1.3.3
|
array.prototype.flatmap: 1.3.3
|
||||||
debug: 3.2.7
|
debug: 3.2.7
|
||||||
doctrine: 2.1.0
|
doctrine: 2.1.0
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@1.21.7)
|
||||||
eslint-import-resolver-node: 0.3.9
|
eslint-import-resolver-node: 0.3.9
|
||||||
eslint-module-utils: 2.12.1(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1))
|
eslint-module-utils: 2.12.1(@typescript-eslint/parser@6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@1.21.7))
|
||||||
hasown: 2.0.2
|
hasown: 2.0.2
|
||||||
is-core-module: 2.16.1
|
is-core-module: 2.16.1
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
|
|
@ -31930,7 +31809,7 @@ snapshots:
|
||||||
string.prototype.trimend: 1.0.9
|
string.prototype.trimend: 1.0.9
|
||||||
tsconfig-paths: 3.15.0
|
tsconfig-paths: 3.15.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@typescript-eslint/parser': 6.21.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.3.3)
|
'@typescript-eslint/parser': 6.21.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.3.3)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- eslint-import-resolver-typescript
|
- eslint-import-resolver-typescript
|
||||||
- eslint-import-resolver-webpack
|
- eslint-import-resolver-webpack
|
||||||
|
|
@ -31965,7 +31844,7 @@ snapshots:
|
||||||
- eslint-import-resolver-webpack
|
- eslint-import-resolver-webpack
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)):
|
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.1(jiti@2.6.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rtsao/scc': 1.1.0
|
'@rtsao/scc': 1.1.0
|
||||||
array-includes: 3.1.9
|
array-includes: 3.1.9
|
||||||
|
|
@ -31976,7 +31855,7 @@ snapshots:
|
||||||
doctrine: 2.1.0
|
doctrine: 2.1.0
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@2.6.1)
|
||||||
eslint-import-resolver-node: 0.3.9
|
eslint-import-resolver-node: 0.3.9
|
||||||
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))
|
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1))
|
||||||
hasown: 2.0.2
|
hasown: 2.0.2
|
||||||
is-core-module: 2.16.1
|
is-core-module: 2.16.1
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
|
|
@ -31994,7 +31873,7 @@ snapshots:
|
||||||
- eslint-import-resolver-webpack
|
- eslint-import-resolver-webpack
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)):
|
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rtsao/scc': 1.1.0
|
'@rtsao/scc': 1.1.0
|
||||||
array-includes: 3.1.9
|
array-includes: 3.1.9
|
||||||
|
|
@ -32005,7 +31884,7 @@ snapshots:
|
||||||
doctrine: 2.1.0
|
doctrine: 2.1.0
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@2.6.1)
|
||||||
eslint-import-resolver-node: 0.3.9
|
eslint-import-resolver-node: 0.3.9
|
||||||
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))
|
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1))
|
||||||
hasown: 2.0.2
|
hasown: 2.0.2
|
||||||
is-core-module: 2.16.1
|
is-core-module: 2.16.1
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
|
|
@ -32033,6 +31912,16 @@ snapshots:
|
||||||
resolve: 1.22.11
|
resolve: 1.22.11
|
||||||
semver: 6.3.1
|
semver: 6.3.1
|
||||||
|
|
||||||
|
eslint-plugin-node@11.1.0(eslint@9.39.1(jiti@1.21.7)):
|
||||||
|
dependencies:
|
||||||
|
eslint: 9.39.1(jiti@1.21.7)
|
||||||
|
eslint-plugin-es: 3.0.1(eslint@9.39.1(jiti@1.21.7))
|
||||||
|
eslint-utils: 2.1.0
|
||||||
|
ignore: 5.3.2
|
||||||
|
minimatch: 3.1.2
|
||||||
|
resolve: 1.22.11
|
||||||
|
semver: 6.3.1
|
||||||
|
|
||||||
eslint-plugin-node@11.1.0(eslint@9.39.1(jiti@2.6.1)):
|
eslint-plugin-node@11.1.0(eslint@9.39.1(jiti@2.6.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@2.6.1)
|
||||||
|
|
@ -32063,6 +31952,16 @@ snapshots:
|
||||||
'@types/eslint': 9.6.1
|
'@types/eslint': 9.6.1
|
||||||
eslint-config-prettier: 8.10.2(eslint@8.57.1)
|
eslint-config-prettier: 8.10.2(eslint@8.57.1)
|
||||||
|
|
||||||
|
eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@8.10.2(eslint@9.39.1(jiti@1.21.7)))(eslint@9.39.1(jiti@1.21.7))(prettier@3.6.2):
|
||||||
|
dependencies:
|
||||||
|
eslint: 9.39.1(jiti@1.21.7)
|
||||||
|
prettier: 3.6.2
|
||||||
|
prettier-linter-helpers: 1.0.0
|
||||||
|
synckit: 0.11.11
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/eslint': 9.6.1
|
||||||
|
eslint-config-prettier: 8.10.2(eslint@9.39.1(jiti@1.21.7))
|
||||||
|
|
||||||
eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@8.10.2(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))(prettier@3.6.2):
|
eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@8.10.2(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))(prettier@3.6.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@2.6.1)
|
||||||
|
|
@ -32087,6 +31986,10 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 8.57.1
|
eslint: 8.57.1
|
||||||
|
|
||||||
|
eslint-plugin-react-hooks@4.6.2(eslint@9.39.1(jiti@1.21.7)):
|
||||||
|
dependencies:
|
||||||
|
eslint: 9.39.1(jiti@1.21.7)
|
||||||
|
|
||||||
eslint-plugin-react-hooks@4.6.2(eslint@9.39.1(jiti@2.6.1)):
|
eslint-plugin-react-hooks@4.6.2(eslint@9.39.1(jiti@2.6.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 9.39.1(jiti@2.6.1)
|
eslint: 9.39.1(jiti@2.6.1)
|
||||||
|
|
@ -32117,6 +32020,28 @@ snapshots:
|
||||||
string.prototype.matchall: 4.0.12
|
string.prototype.matchall: 4.0.12
|
||||||
string.prototype.repeat: 1.0.0
|
string.prototype.repeat: 1.0.0
|
||||||
|
|
||||||
|
eslint-plugin-react@7.37.5(eslint@9.39.1(jiti@1.21.7)):
|
||||||
|
dependencies:
|
||||||
|
array-includes: 3.1.9
|
||||||
|
array.prototype.findlast: 1.2.5
|
||||||
|
array.prototype.flatmap: 1.3.3
|
||||||
|
array.prototype.tosorted: 1.1.4
|
||||||
|
doctrine: 2.1.0
|
||||||
|
es-iterator-helpers: 1.2.1
|
||||||
|
eslint: 9.39.1(jiti@1.21.7)
|
||||||
|
estraverse: 5.3.0
|
||||||
|
hasown: 2.0.2
|
||||||
|
jsx-ast-utils: 3.3.5
|
||||||
|
minimatch: 3.1.2
|
||||||
|
object.entries: 1.1.9
|
||||||
|
object.fromentries: 2.0.8
|
||||||
|
object.values: 1.2.1
|
||||||
|
prop-types: 15.8.1
|
||||||
|
resolve: 2.0.0-next.5
|
||||||
|
semver: 6.3.1
|
||||||
|
string.prototype.matchall: 4.0.12
|
||||||
|
string.prototype.repeat: 1.0.0
|
||||||
|
|
||||||
eslint-plugin-react@7.37.5(eslint@9.39.1(jiti@2.6.1)):
|
eslint-plugin-react@7.37.5(eslint@9.39.1(jiti@2.6.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
array-includes: 3.1.9
|
array-includes: 3.1.9
|
||||||
|
|
@ -33336,6 +33261,53 @@ snapshots:
|
||||||
- supports-color
|
- supports-color
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
expo-router@6.0.15(jiucxy5ca3jdtbnulaxuc46jdq):
|
||||||
|
dependencies:
|
||||||
|
'@expo/metro-runtime': 6.1.2(expo@54.0.25)(react-dom@19.1.0(react@19.1.0))(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0)
|
||||||
|
'@expo/schema-utils': 0.1.7
|
||||||
|
'@radix-ui/react-slot': 1.2.0(@types/react@19.2.7)(react@19.1.0)
|
||||||
|
'@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
|
'@react-navigation/bottom-tabs': 7.8.6(@react-navigation/native@7.1.21(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0)
|
||||||
|
'@react-navigation/native': 7.1.21(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0)
|
||||||
|
'@react-navigation/native-stack': 7.8.0(@react-navigation/native@7.1.21(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0)
|
||||||
|
client-only: 0.0.1
|
||||||
|
debug: 4.4.3
|
||||||
|
escape-string-regexp: 4.0.0
|
||||||
|
expo: 54.0.25(@babel/core@7.28.5)(@expo/metro-runtime@6.1.2)(expo-router@6.0.15)(react-native-webview@13.12.2(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0)
|
||||||
|
expo-constants: 18.0.10(expo@54.0.25)(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))
|
||||||
|
expo-linking: 8.0.9(expo@54.0.25)(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0)
|
||||||
|
expo-server: 1.0.4
|
||||||
|
fast-deep-equal: 3.1.3
|
||||||
|
invariant: 2.2.4
|
||||||
|
nanoid: 3.3.11
|
||||||
|
query-string: 7.1.3
|
||||||
|
react: 19.1.0
|
||||||
|
react-fast-compare: 3.2.2
|
||||||
|
react-native: 0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0)
|
||||||
|
react-native-is-edge-to-edge: 1.2.1(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0)
|
||||||
|
react-native-safe-area-context: 5.6.2(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0)
|
||||||
|
react-native-screens: 4.16.0(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0)
|
||||||
|
semver: 7.6.3
|
||||||
|
server-only: 0.0.1
|
||||||
|
sf-symbols-typescript: 2.1.0
|
||||||
|
shallowequal: 1.1.0
|
||||||
|
use-latest-callback: 0.2.6(react@19.1.0)
|
||||||
|
vaul: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
|
optionalDependencies:
|
||||||
|
'@react-navigation/drawer': 7.7.4(@react-navigation/native@7.1.21(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native-gesture-handler@2.28.0(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@0.6.1(@babel/core@7.28.5)(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0)
|
||||||
|
'@testing-library/react-native': 13.3.3(jest@30.2.0(@types/node@20.19.25)(esbuild-register@3.6.0(esbuild@0.27.0)))(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react-test-renderer@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
|
react-dom: 19.1.0(react@19.1.0)
|
||||||
|
react-native-gesture-handler: 2.28.0(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0)
|
||||||
|
react-native-reanimated: 4.1.5(@babel/core@7.28.5)(react-native-worklets@0.6.1(@babel/core@7.28.5)(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0))(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0)
|
||||||
|
react-native-web: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
|
react-server-dom-webpack: 19.0.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(webpack@5.100.2(esbuild@0.27.0))
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@react-native-masked-view/masked-view'
|
||||||
|
- '@types/react'
|
||||||
|
- '@types/react-dom'
|
||||||
|
- supports-color
|
||||||
|
optional: true
|
||||||
|
|
||||||
expo-router@6.0.15(nttrd3tw67nnyhowcwgdzipb5e):
|
expo-router@6.0.15(nttrd3tw67nnyhowcwgdzipb5e):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@expo/metro-runtime': 6.1.2(expo@54.0.25)(react-dom@19.1.0(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0)
|
'@expo/metro-runtime': 6.1.2(expo@54.0.25)(react-dom@19.1.0(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.2.7)(react@19.1.0))(react@19.1.0)
|
||||||
|
|
@ -35525,6 +35497,26 @@ snapshots:
|
||||||
- supports-color
|
- supports-color
|
||||||
- ts-node
|
- ts-node
|
||||||
|
|
||||||
|
jest-cli@30.2.0(@types/node@20.19.25)(esbuild-register@3.6.0(esbuild@0.27.0)):
|
||||||
|
dependencies:
|
||||||
|
'@jest/core': 30.2.0(esbuild-register@3.6.0(esbuild@0.27.0))
|
||||||
|
'@jest/test-result': 30.2.0
|
||||||
|
'@jest/types': 30.2.0
|
||||||
|
chalk: 4.1.2
|
||||||
|
exit-x: 0.2.2
|
||||||
|
import-local: 3.2.0
|
||||||
|
jest-config: 30.2.0(@types/node@20.19.25)(esbuild-register@3.6.0(esbuild@0.27.0))
|
||||||
|
jest-util: 30.2.0
|
||||||
|
jest-validate: 30.2.0
|
||||||
|
yargs: 17.7.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@types/node'
|
||||||
|
- babel-plugin-macros
|
||||||
|
- esbuild-register
|
||||||
|
- supports-color
|
||||||
|
- ts-node
|
||||||
|
optional: true
|
||||||
|
|
||||||
jest-cli@30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)):
|
jest-cli@30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jest/core': 30.2.0(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3))
|
'@jest/core': 30.2.0(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3))
|
||||||
|
|
@ -35696,6 +35688,40 @@ snapshots:
|
||||||
- babel-plugin-macros
|
- babel-plugin-macros
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
jest-config@30.2.0(@types/node@20.19.25)(esbuild-register@3.6.0(esbuild@0.27.0)):
|
||||||
|
dependencies:
|
||||||
|
'@babel/core': 7.28.5
|
||||||
|
'@jest/get-type': 30.1.0
|
||||||
|
'@jest/pattern': 30.0.1
|
||||||
|
'@jest/test-sequencer': 30.2.0
|
||||||
|
'@jest/types': 30.2.0
|
||||||
|
babel-jest: 30.2.0(@babel/core@7.28.5)
|
||||||
|
chalk: 4.1.2
|
||||||
|
ci-info: 4.3.1
|
||||||
|
deepmerge: 4.3.1
|
||||||
|
glob: 10.5.0
|
||||||
|
graceful-fs: 4.2.11
|
||||||
|
jest-circus: 30.2.0
|
||||||
|
jest-docblock: 30.2.0
|
||||||
|
jest-environment-node: 30.2.0
|
||||||
|
jest-regex-util: 30.0.1
|
||||||
|
jest-resolve: 30.2.0
|
||||||
|
jest-runner: 30.2.0
|
||||||
|
jest-util: 30.2.0
|
||||||
|
jest-validate: 30.2.0
|
||||||
|
micromatch: 4.0.8
|
||||||
|
parse-json: 5.2.0
|
||||||
|
pretty-format: 30.2.0
|
||||||
|
slash: 3.0.0
|
||||||
|
strip-json-comments: 3.1.1
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/node': 20.19.25
|
||||||
|
esbuild-register: 3.6.0(esbuild@0.27.0)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- babel-plugin-macros
|
||||||
|
- supports-color
|
||||||
|
optional: true
|
||||||
|
|
||||||
jest-config@30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)):
|
jest-config@30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.28.5
|
'@babel/core': 7.28.5
|
||||||
|
|
@ -36386,6 +36412,20 @@ snapshots:
|
||||||
- supports-color
|
- supports-color
|
||||||
- ts-node
|
- ts-node
|
||||||
|
|
||||||
|
jest@30.2.0(@types/node@20.19.25)(esbuild-register@3.6.0(esbuild@0.27.0)):
|
||||||
|
dependencies:
|
||||||
|
'@jest/core': 30.2.0(esbuild-register@3.6.0(esbuild@0.27.0))
|
||||||
|
'@jest/types': 30.2.0
|
||||||
|
import-local: 3.2.0
|
||||||
|
jest-cli: 30.2.0(@types/node@20.19.25)(esbuild-register@3.6.0(esbuild@0.27.0))
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@types/node'
|
||||||
|
- babel-plugin-macros
|
||||||
|
- esbuild-register
|
||||||
|
- supports-color
|
||||||
|
- ts-node
|
||||||
|
optional: true
|
||||||
|
|
||||||
jest@30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)):
|
jest@30.2.0(@types/node@22.19.1)(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jest/core': 30.2.0(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3))
|
'@jest/core': 30.2.0(esbuild-register@3.6.0(esbuild@0.19.12))(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3))
|
||||||
|
|
@ -42540,23 +42580,6 @@ snapshots:
|
||||||
lightningcss: 1.30.2
|
lightningcss: 1.30.2
|
||||||
terser: 5.44.1
|
terser: 5.44.1
|
||||||
|
|
||||||
vite@6.4.1(@types/node@20.19.25)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1):
|
|
||||||
dependencies:
|
|
||||||
esbuild: 0.25.12
|
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
|
||||||
picomatch: 4.0.3
|
|
||||||
postcss: 8.5.6
|
|
||||||
rollup: 4.53.3
|
|
||||||
tinyglobby: 0.2.15
|
|
||||||
optionalDependencies:
|
|
||||||
'@types/node': 20.19.25
|
|
||||||
fsevents: 2.3.3
|
|
||||||
jiti: 1.21.7
|
|
||||||
lightningcss: 1.30.2
|
|
||||||
terser: 5.44.1
|
|
||||||
tsx: 4.20.6
|
|
||||||
yaml: 2.8.1
|
|
||||||
|
|
||||||
vite@6.4.1(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1):
|
vite@6.4.1(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.12
|
esbuild: 0.25.12
|
||||||
|
|
@ -42659,10 +42682,6 @@ snapshots:
|
||||||
tsx: 4.20.6
|
tsx: 4.20.6
|
||||||
yaml: 2.8.1
|
yaml: 2.8.1
|
||||||
|
|
||||||
vitefu@1.1.1(vite@6.4.1(@types/node@20.19.25)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)):
|
|
||||||
optionalDependencies:
|
|
||||||
vite: 6.4.1(@types/node@20.19.25)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)
|
|
||||||
|
|
||||||
vitefu@1.1.1(vite@6.4.1(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)):
|
vitefu@1.1.1(vite@6.4.1(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)):
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 6.4.1(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)
|
vite: 6.4.1(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)
|
||||||
|
|
|
||||||
|
|
@ -229,24 +229,28 @@ const APP_CONFIGS = [
|
||||||
path: 'apps/picture/apps/backend/.env',
|
path: 'apps/picture/apps/backend/.env',
|
||||||
vars: {
|
vars: {
|
||||||
NODE_ENV: () => 'development',
|
NODE_ENV: () => 'development',
|
||||||
PORT: (env) => env.PICTURE_BACKEND_PORT || '3003',
|
PORT: (env) => env.PICTURE_BACKEND_PORT || '3006',
|
||||||
BACKEND_URL: (env) => env.PICTURE_BACKEND_URL || 'http://localhost:3003',
|
BACKEND_URL: (env) => env.PICTURE_BACKEND_URL || 'http://localhost:3006',
|
||||||
DATABASE_URL: (env) =>
|
DATABASE_URL: (env) =>
|
||||||
env.PICTURE_DATABASE_URL || 'postgresql://picture:picturepassword@localhost:5434/picture',
|
env.PICTURE_DATABASE_URL || 'postgresql://manacore:devpassword@localhost:5432/picture',
|
||||||
MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL,
|
MANA_CORE_AUTH_URL: (env) => env.MANA_CORE_AUTH_URL,
|
||||||
DEV_BYPASS_AUTH: () => 'true',
|
DEV_BYPASS_AUTH: () => 'true',
|
||||||
DEV_USER_ID: (env) => env.DEV_USER_ID || '00000000-0000-0000-0000-000000000000',
|
DEV_USER_ID: (env) => env.DEV_USER_ID || '00000000-0000-0000-0000-000000000000',
|
||||||
REPLICATE_API_TOKEN: (env) => env.MAERCHENZAUBER_REPLICATE_API_KEY,
|
REPLICATE_API_TOKEN: (env) => env.PICTURE_REPLICATE_API_TOKEN,
|
||||||
CORS_ORIGINS: (env) => env.CORS_ORIGINS,
|
CORS_ORIGINS: (env) => env.CORS_ORIGINS,
|
||||||
// Storage configuration
|
// Storage configuration - use shared MinIO for local dev
|
||||||
STORAGE_MODE: (env) => env.PICTURE_STORAGE_MODE || 'local',
|
STORAGE_MODE: (env) => env.PICTURE_STORAGE_MODE || 's3',
|
||||||
LOCAL_STORAGE_PATH: (env) => env.PICTURE_LOCAL_STORAGE_PATH || './uploads',
|
LOCAL_STORAGE_PATH: (env) => env.PICTURE_LOCAL_STORAGE_PATH || './uploads',
|
||||||
S3_ENDPOINT: (env) => env.PICTURE_S3_ENDPOINT || '',
|
S3_ENDPOINT: (env) => env.S3_ENDPOINT || 'http://localhost:9000',
|
||||||
S3_REGION: (env) => env.PICTURE_S3_REGION || 'eu-central-1',
|
S3_REGION: (env) => env.S3_REGION || 'us-east-1',
|
||||||
S3_ACCESS_KEY: (env) => env.PICTURE_S3_ACCESS_KEY || '',
|
S3_ACCESS_KEY: (env) => env.S3_ACCESS_KEY || 'minioadmin',
|
||||||
S3_SECRET_KEY: (env) => env.PICTURE_S3_SECRET_KEY || '',
|
S3_SECRET_KEY: (env) => env.S3_SECRET_KEY || 'minioadmin',
|
||||||
S3_BUCKET: (env) => env.PICTURE_S3_BUCKET || 'picture-uploads',
|
S3_BUCKET: (env) => env.PICTURE_S3_BUCKET || 'picture-storage',
|
||||||
STORAGE_PUBLIC_URL: (env) => env.PICTURE_STORAGE_PUBLIC_URL || '',
|
STORAGE_PUBLIC_URL: (env) =>
|
||||||
|
env.PICTURE_STORAGE_PUBLIC_URL || 'http://localhost:9000/picture-storage',
|
||||||
|
// Credit system (for staging)
|
||||||
|
APP_ID: (env) => env.PICTURE_APP_ID || 'picture-app',
|
||||||
|
MANA_CORE_SERVICE_KEY: (env) => env.PICTURE_MANA_CORE_SERVICE_KEY || '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue