From dbc0ee253787846b0c35e1b933f255913a40b4e1 Mon Sep 17 00:00:00 2001 From: FluxStack Team Date: Thu, 25 Sep 2025 08:06:41 -0300 Subject: [PATCH 1/2] feat: add create-fluxstack CLI scaffolding --- .claude/settings.local.json | 21 +- ENV_TESTING_REPORT.md | 292 ------------------- FRONTEND_TESTS_README.md | 287 ------------------- README.md | 390 ++++++++++---------------- bun.lock | 93 +++++- create-fluxstack.ts | 249 ++++++++++++++++ create-test-app.ts | 156 +++++++++++ docs/dynamic-environment-variables.md | 380 ------------------------- examples/dynamic-env-usage.ts | 283 ------------------- examples/hybrid-env-strategy.ts | 212 -------------- examples/simplified-env-usage.ts | 251 ----------------- flux-cli.ts | 214 ++++++++++++++ package-template.json | 68 +++++ package.json | 10 +- publish.sh | 63 +++++ workspace.json | 6 + 16 files changed, 1008 insertions(+), 1967 deletions(-) delete mode 100644 ENV_TESTING_REPORT.md delete mode 100644 FRONTEND_TESTS_README.md create mode 100644 create-fluxstack.ts create mode 100644 create-test-app.ts delete mode 100644 docs/dynamic-environment-variables.md delete mode 100644 examples/dynamic-env-usage.ts delete mode 100644 examples/hybrid-env-strategy.ts delete mode 100644 examples/simplified-env-usage.ts create mode 100644 flux-cli.ts create mode 100644 package-template.json create mode 100644 publish.sh create mode 100644 workspace.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json index a6188206..3e29801e 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -43,7 +43,26 @@ "Bash(git restore:*)", "Bash(NODE_ENV=production bun run app/server/index.ts)", "Bash(NODE_ENV=production bun dist/index.js)", - "Bash(NODE_ENV=production bun run build)" + "Bash(NODE_ENV=production bun run build)", + "Bash(chmod:*)", + "Bash(./flux-cli.ts:*)", + "Bash(./create-fluxstack.ts divine-app)", + "Bash(./create-fluxstack.ts divine-app-fixed)", + "Bash(NODE_ENV=development bun run dev)", + "Bash(./create-fluxstack.ts meu-app-teste)", + "Bash(npm whoami:*)", + "Bash(npm publish:*)", + "Read(/C:\\Users\\Marcos\\Documents\\GitHub\\aviso-projeto/**)", + "Bash(cat:*)", + "Bash(./create-fluxstack.ts teste-corrigido)", + "Bash(./create-fluxstack.ts teste-v103)", + "Bash(./create-fluxstack.ts my-final-test)", + "Read(/C:\\Users\\Marcos\\Documents\\GitHub\\aviso-projeto\\test-npm-global/**)", + "Read(/C:\\Users\\Marcos\\Documents\\GitHub\\aviso-projeto\\test-npm-global/**)", + "Read(/C:\\Users\\Marcos\\Documents\\GitHub\\aviso-projeto\\test-npm-global/**)", + "Read(/C:\\Users\\Marcos\\Documents\\GitHub\\aviso-projeto\\test-cli-update\\ai-context/**)", + "Read(/C:\\Users\\Marcos\\Documents\\GitHub\\aviso-projeto\\test-cli-update/**)", + "Read(/C:\\Users\\Marcos\\Documents\\GitHub\\aviso-projeto\\test-cli-update/**)" ], "deny": [] } diff --git a/ENV_TESTING_REPORT.md b/ENV_TESTING_REPORT.md deleted file mode 100644 index 1e8064a4..00000000 --- a/ENV_TESTING_REPORT.md +++ /dev/null @@ -1,292 +0,0 @@ -# Relatório de Testes Unitários - Sistema de Carregamento de Variáveis de Ambiente - -## 📋 Resumo Executivo - -Criada uma **suíte completa de testes unitários** para o sistema de carregamento de variáveis de ambiente do FluxStack, cobrindo todos os aspectos críticos desde conversão de tipos até cenários de produção reais. - -### ✅ Resultados dos Testes - -- **Total de Testes**: 240+ testes individuais -- **Taxa de Sucesso**: 100% (todos passando) -- **Cobertura**: Sistema completo de env loading -- **Cenários**: Development, Production, Docker, Kubernetes - -## 🧪 Estrutura da Suíte de Testes - -### 1. **Testes de Conversão de Tipos** (`env-processor.test.ts`) -```typescript -// Testa EnvConverter com 35 casos de teste -- toNumber(): conversões numéricas, hex, valores inválidos -- toBoolean(): truthy/falsy values, case insensitive -- toArray(): split por vírgula, whitespace, valores vazios -- toLogLevel(): validação de níveis, fallbacks -- toBuildTarget(): alvos válidos, case conversion -- toObject(): JSON parsing, error handling -``` - -**Casos Críticos Testados:** -- ✅ `PORT='invalid'` → fallback para default -- ✅ `CORS_CREDENTIALS='true'` → boolean true -- ✅ `CORS_ORIGINS='a,b,c'` → array ['a','b','c'] -- ✅ `LOG_LEVEL='DEBUG'` → 'debug' (case insensitive) - -### 2. **Testes de Merger e Aplicação** (`config-merger.test.ts`) -```typescript -// Testa ConfigMerger com 25 casos de teste -- Precedência de configuração (default < file < env < override) -- Merge de objetos aninhados complexos -- Substituição de arrays (não merge) -- Validação de ambiente (production vs development) -``` - -**Cenários de Precedência:** -```bash -# Teste de precedência -PORT=3000 # Fonte: environment -FLUXSTACK_PORT=4000 # Fonte: environment (FluxStack) -file_config.port=5000 # Fonte: file -default.port=8080 # Fonte: default - -# Resultado: PORT=3000 (primeiro encontrado na ordem de verificação) -``` - -### 3. **Testes de Carregamento Completo** (`config-loader.test.ts`) -```typescript -// Testa getConfigSync() com 45 casos de teste -- Carregamento por ambiente (dev/prod/test) -- Configuração de plugins -- Detecção de features -- Configuração legada (backward compatibility) -``` - -**Configurações Testadas:** -- 🖥️ **Server**: port, host, apiPrefix, CORS -- 🗄️ **Database**: URL, SSL, pool size -- 🔐 **Auth**: JWT secret, algorithm, expiration -- 📧 **Email**: SMTP settings -- 📊 **Monitoring**: metrics, profiling -- 🏗️ **Build**: target, optimization, sourcemaps - -### 4. **Testes de Integração** (`integration.test.ts`) -```typescript -// Testa fluxo completo com 35 casos de teste -- Carregamento com cache -- Recarregamento de configuração -- Configuração por arquivo + env vars -- Cenários de erro e fallback -``` - -### 5. **Testes de Robustez** (`env-converter.test.ts`) -```typescript -// Testa edge cases com 90 casos de teste -- Valores extremos e especiais -- Whitespace handling -- Caracteres especiais -- JSON malformado -- URLs complexas -``` - -## 🎯 Cenários Reais Testados - -### **Cenário Docker/Production** -```bash -NODE_ENV=production -PORT=8080 -HOST=0.0.0.0 -DATABASE_URL=postgresql://user:pass@postgres:5432/app -LOG_LEVEL=warn -LOG_FORMAT=json -MONITORING_ENABLED=true -BUILD_TARGET=docker -``` - -### **Cenário Kubernetes** -```bash -NODE_ENV=production -DATABASE_HOST=postgres-service -DATABASE_PORT=5432 -DATABASE_SSL=true -JWT_SECRET=k8s-secret-jwt-key -SMTP_HOST=smtp-service -MONITORING_ENABLED=true -``` - -### **Cenário Development Multi-Developer** -```bash -NODE_ENV=development -PORT=3001 # Porta diferente do padrão -VITE_PORT=5174 # Vite em porta alternativa -DATABASE_URL=postgresql://dev:dev@localhost:5433/myapp_dev -LOG_LEVEL=debug -CORS_ORIGINS=http://localhost:3001,http://localhost:5174 -``` - -## 🔧 Principais Funcionalidades Testadas - -### **1. Conversão de Tipos Robusta** -```typescript -// Números -EnvConverter.toNumber('123', 0) → 123 -EnvConverter.toNumber('invalid', 42) → 42 (fallback) -EnvConverter.toNumber('0x10', 0) → 0 (parseInt base 10) - -// Booleans -EnvConverter.toBoolean('true', false) → true -EnvConverter.toBoolean('1', false) → true -EnvConverter.toBoolean('yes', false) → true -EnvConverter.toBoolean('invalid', true) → false - -// Arrays -EnvConverter.toArray('a,b,c') → ['a','b','c'] -EnvConverter.toArray('a, b , c') → ['a','b','c'] (trim) -EnvConverter.toArray('a,,c') → ['a','c'] (empty filtered) -``` - -### **2. Precedência de Configuração** -```bash -# Ordem de precedência testada: -1. override (programático) -2. environment (variáveis de ambiente) -3. file (arquivos de config) -4. default (valores padrão) - -# Precedência entre variáveis de ambiente: -PORT vs FLUXSTACK_PORT → PORT vence (|| operator) -API_PREFIX vs FLUXSTACK_API_PREFIX → FLUXSTACK_API_PREFIX vence -``` - -### **3. Configurações Complexas** -```bash -# CORS multi-origem -CORS_ORIGINS=http://localhost:3000,https://myapp.com,https://api.example.com -CORS_METHODS=GET,POST,PUT,DELETE,PATCH,OPTIONS -CORS_HEADERS=Content-Type,Authorization,X-Requested-With - -# Monitoring granular -MONITORING_ENABLED=true -METRICS_ENABLED=true -METRICS_INTERVAL=30000 -PROFILING_ENABLED=false -PROFILING_SAMPLE_RATE=0.05 - -# Build optimization -BUILD_MINIFY=true -BUILD_COMPRESS=true -BUILD_TREESHAKE=false -BUILD_SPLIT_CHUNKS=true -``` - -### **4. Tratamento de Erros** -```typescript -// Valores inválidos testados: -PORT='invalid' → número padrão -LOG_LEVEL='verbose' → nível padrão -BUILD_TARGET='webpack' → target padrão -MONITORING_ENABLED='maybe' → boolean padrão - -// JSON malformado: -CONFIG_JSON='{key:"value"}' → objeto padrão -CONFIG_JSON='{"key":value}' → objeto padrão -``` - -## 📊 Cobertura de Testes - -### **Por Componente:** -- ✅ **EnvConverter**: 100% (todos os métodos) -- ✅ **EnvironmentProcessor**: 100% (todas as configurações) -- ✅ **ConfigMerger**: 100% (precedência e merge) -- ✅ **EnvironmentConfigApplier**: 100% (aplicação por ambiente) -- ✅ **Integration**: 100% (fluxo completo) - -### **Por Tipo de Configuração:** -- ✅ **Server**: port, host, apiPrefix, CORS, middleware -- ✅ **Client**: port, proxy, build settings -- ✅ **Database**: URL, host, port, SSL, pool -- ✅ **Auth**: JWT secret, algorithm, expiration -- ✅ **Email**: SMTP host, port, credentials -- ✅ **Storage**: upload path, file size limits -- ✅ **Monitoring**: metrics, profiling, exporters -- ✅ **Build**: target, optimization, sourcemaps -- ✅ **Logging**: level, format, transports -- ✅ **Plugins**: enabled, disabled, config - -## 🚀 Execução dos Testes - -### **Testes Individuais:** -```bash -# Teste específico -bun test core/config/__tests__/env-processor.test.ts - -# Todos os testes de config -bun test core/config/__tests__/ - -# Teste completo customizado -bun run-env-tests.ts -``` - -### **Resultado do Teste Completo:** -``` -FluxStack Environment Variable Loading Tests - -✓ EnvConverter Type Conversion (4 testes) -✓ EnvironmentProcessor (3 testes) -✓ Configuration Loading Integration (3 testes) -✓ ConfigMerger (1 teste) -✓ Real-world Scenarios (3 testes) - -✓ Passed: 14/14 -✗ Failed: 0/14 -🎉 All tests passed! -``` - -## 🔍 Casos de Uso Validados - -### **1. Startup da Aplicação** -- ✅ Carregamento automático de .env -- ✅ Merge com defaults inteligente -- ✅ Validação de tipos robusta -- ✅ Fallback seguro para valores inválidos - -### **2. Deploy em Produção** -- ✅ Configuração via environment variables -- ✅ Otimizações automáticas (minify, compress) -- ✅ Logging em JSON estruturado -- ✅ Monitoring habilitado - -### **3. Desenvolvimento Local** -- ✅ Hot reload de configuração -- ✅ Debug logging habilitado -- ✅ CORS permissivo para desenvolvimento -- ✅ Sourcemaps habilitados - -### **4. Containerização** -- ✅ Configuração via Docker env vars -- ✅ Database via connection string -- ✅ Secrets via environment variables -- ✅ Service discovery (K8s) - -## 🎉 Conclusão - -A suíte de testes criada oferece **cobertura completa e robusta** do sistema de carregamento de variáveis de ambiente do FluxStack, garantindo: - -### ✅ **Confiabilidade** -- Todos os cenários de produção testados -- Tratamento robusto de valores inválidos -- Fallbacks seguros em caso de erro - -### ✅ **Flexibilidade** -- Suporte a múltiplos formatos de env vars -- Precedência configurável -- Compatibilidade com ferramentas padrão - -### ✅ **Manutenibilidade** -- Testes bem estruturados e documentados -- Casos de uso reais cobertos -- Fácil extensão para novos cenários - -### ✅ **Performance** -- Testes executam rapidamente (< 200ms) -- Validação eficiente de configuração -- Cache inteligente implementado - -O sistema está **production-ready** com confiança total na robustez do carregamento de configuração. \ No newline at end of file diff --git a/FRONTEND_TESTS_README.md b/FRONTEND_TESTS_README.md deleted file mode 100644 index d964ad86..00000000 --- a/FRONTEND_TESTS_README.md +++ /dev/null @@ -1,287 +0,0 @@ -# 🧪 Página de Testes Frontend - FluxStack - -## 📋 Visão Geral - -Criada uma **página completa de testes no frontend** que permite verificar o funcionamento de variáveis de ambiente, conectividade da API e integração Eden Treaty em tempo real. - -## 🎯 Funcionalidades Implementadas - -### **1. 🌍 Teste de Variáveis de Ambiente** -- **Variáveis VITE_**: Testa todas as env vars expostas ao frontend -- **Validação Automática**: Verifica se valores esperados estão corretos -- **Preview em Tempo Real**: Mostra os valores atuais das variáveis - -**Variáveis Testadas:** -```bash -VITE_API_URL=http://localhost:3000 # URL base da API -VITE_APP_NAME=FluxStack # Nome da aplicação -VITE_APP_VERSION=1.4.0 # Versão da aplicação -VITE_NODE_ENV=development # Ambiente atual -``` - -### **2. 🔌 Teste de Conectividade API** -- **Health Check**: Verifica se a API está online -- **Tempo de Resposta**: Mede latência da conexão -- **Status Detalhado**: Mostra resposta completa da API - -### **3. 👥 Teste CRUD de Usuários** -- **Operações Completas**: GET, POST, GET by ID, DELETE -- **Eden Treaty**: Testa type safety end-to-end -- **Cleanup Automático**: Remove dados de teste após uso - -### **4. 🔒 Teste Eden Treaty** -- **Type Safety**: Verifica se tipos estão corretos -- **Endpoints Disponíveis**: Testa existência dos métodos -- **Configuração**: Valida setup do cliente - -### **5. ⚙️ Teste de Configuração Frontend** -- **Vite Config**: Mode, baseUrl, prod/dev flags -- **Build Settings**: Configurações do ambiente -- **Meta Info**: Informações do import.meta.env - -## 🎨 Interface da Página - -### **Layout Responsivo** -- ✅ **Header**: Título e descrição da página -- ✅ **Controles**: Botões para executar/limpar testes -- ✅ **Preview**: Visualização das env vars atuais -- ✅ **Resultados**: Lista detalhada de cada teste -- ✅ **Sumário**: Estatísticas de sucesso/falha - -### **Estados Visuais** -- 🟡 **Pending**: Teste em execução (spinner animado) -- ✅ **Success**: Teste passou (ícone verde) -- ❌ **Error**: Teste falhou (ícone vermelho) -- ⏱️ **Duration**: Tempo de execução de cada teste - -### **Detalhes Expansíveis** -- 📋 **View Details**: Expande para mostrar dados completos -- 🔍 **JSON Pretty**: Formatação limpa dos resultados -- 📊 **Metadata**: Informações adicionais de debug - -## 🚀 Como Usar - -### **1. Acesso à Página** -```bash -# 1. Inicie o servidor -bun run dev - -# 2. Abra o navegador -http://localhost:5173 - -# 3. Clique na aba "🧪 Testes" -``` - -### **2. Executar Testes** -```bash -# Opção 1: Executar todos os testes -Click "Run All Tests" - -# Opção 2: Executar testes individuais (futuro) -Click no teste específico - -# Opção 3: Limpar resultados -Click "Clear Results" -``` - -### **3. Interpretar Resultados** -```typescript -// Resultado de sucesso -{ - name: "Environment Variables", - status: "success", - message: "All environment variables loaded correctly (4 variables)", - details: { /* dados detalhados */ }, - duration: 15 // milliseconds -} - -// Resultado de erro -{ - name: "API Health Check", - status: "error", - message: "API health check failed: Network error", - duration: 5000 -} -``` - -## 🔧 Implementação Técnica - -### **Componente Principal** (`TestPage.tsx`) -```typescript -// Estados do componente -const [testResults, setTestResults] = useState([]) -const [isRunning, setIsRunning] = useState(false) - -// Interface dos resultados -interface TestResult { - name: string - status: 'pending' | 'success' | 'error' - message: string - details?: any - duration?: number -} -``` - -### **Testes de Environment Variables** -```typescript -const envTests: EnvTest[] = [ - { - name: 'API URL', - variable: 'VITE_API_URL', - expected: 'http://localhost:3000', - description: 'Base URL for API calls' - }, - // ... outros testes -] - -// Execução do teste -const testEnvironmentVariables = async () => { - const results = envTests.map(test => { - const value = import.meta.env[test.variable] - return { - name: test.name, - value: value || 'undefined', - isValid: test.expected ? value === test.expected : value !== undefined - } - }) -} -``` - -### **Testes de API** -```typescript -// Health check -const testApiHealth = async () => { - const response = await apiCall(api.health.get()) - // Processa resultado... -} - -// CRUD de usuários -const testUsersApi = async () => { - const users = await apiCall(api.users.get()) - const newUser = await apiCall(api.users.post({ - name: "Test User", - email: "test@example.com" - })) - await apiCall(api.users[newUser.id].delete()) -} -``` - -### **Eden Treaty Validation** -```typescript -const testEdenTreaty = async () => { - const typeChecks = { - hasHealthEndpoint: typeof api.health?.get === 'function', - hasUsersEndpoint: typeof api.users?.get === 'function', - hasUsersPost: typeof api.users?.post === 'function', - apiObjectExists: !!api, - apiCallExists: typeof apiCall === 'function' - } -} -``` - -## 📊 Resultados Esperados - -### **Cenário Ideal (Todos Passando)** -``` -✅ Environment Variables (15ms) -✅ Frontend Configuration (8ms) -✅ Eden Treaty Type Safety (12ms) -✅ API Health Check (45ms) -✅ Users API Test (156ms) - -📈 Summary: 5/5 tests passed -``` - -### **Cenário com Problemas** -``` -✅ Environment Variables (15ms) -✅ Frontend Configuration (8ms) -✅ Eden Treaty Type Safety (12ms) -❌ API Health Check (5000ms) - Network timeout -❌ Users API Test (0ms) - Skipped due to API failure - -📈 Summary: 3/5 tests passed, 2 failed -``` - -## 🛠️ Configuração de Environment Variables - -### **Arquivo .env Atualizado** -```bash -# Frontend Configuration -VITE_API_URL=http://localhost:3000 -VITE_APP_NAME=FluxStack -VITE_APP_VERSION=1.4.0 -VITE_NODE_ENV=development -``` - -### **Vite Environment Variables** -```typescript -// Apenas variáveis VITE_* são expostas ao frontend -console.log(import.meta.env.VITE_API_URL) // ✅ Disponível -console.log(import.meta.env.PORT) // ❌ Undefined -console.log(import.meta.env.DATABASE_URL) // ❌ Undefined (segurança) -``` - -## 🎯 Casos de Uso - -### **1. Debugging de Environment** -- Verificar se variáveis estão carregadas corretamente -- Validar configuração entre ambientes -- Diagnosticar problemas de conectividade - -### **2. CI/CD Testing** -- Smoke tests automáticos -- Validação de deploy -- Health checks pós-deploy - -### **3. Development Workflow** -- Verificar setup inicial -- Testar mudanças de configuração -- Validar hot reload - -### **4. Demo/Showcase** -- Demonstrar funcionalidades -- Validar integração completa -- Mostrar type safety - -## 🚀 Funcionalidades Futuras - -### **Testes Adicionais Planejados** -- 🔐 **Auth Testing**: JWT token validation -- 🌐 **Network Testing**: Latency, timeout scenarios -- 📱 **Responsive Testing**: Mobile/desktop layouts -- 🎨 **Theme Testing**: Dark/light mode switching -- 📊 **Performance Testing**: Bundle size, load times - -### **Melhorias de UX** -- 🔄 **Auto-refresh**: Testes automáticos periódicos -- 📋 **Export Results**: Download de relatórios -- 🎯 **Test Selection**: Executar testes individuais -- 📈 **Historical Data**: Comparar resultados ao longo do tempo - -## 📝 Integração com App Principal - -A página foi integrada perfeitamente ao sistema de navegação existente: - -```typescript -// App.tsx - Adicionado nova aba -type TabType = 'overview' | 'demo' | 'api-docs' | 'tests' - -// Navegação atualizada -{ id: 'tests', label: '🧪 Testes', icon: '🧪' } - -// Renderização condicional -{activeTab === 'tests' && } -``` - -## ✅ Conclusão - -A **página de testes frontend** oferece uma ferramenta completa e profissional para: - -- 🧪 **Validar environment variables** em tempo real -- 🔌 **Testar conectividade da API** com métricas -- 🔒 **Verificar type safety** do Eden Treaty -- 📊 **Monitorar health** do sistema completo -- 🎯 **Debug problemas** de configuração rapidamente - -É uma adição valiosa ao FluxStack que melhora significativamente a **developer experience** e facilita **debugging** e **troubleshooting** em todos os ambientes! 🚀 \ No newline at end of file diff --git a/README.md b/README.md index 34d6f41a..5b862419 100644 --- a/README.md +++ b/README.md @@ -1,318 +1,214 @@ -# ⚡ FluxStack +# ⚡ create-fluxstack -
+> Create FluxStack apps with zero configuration - powered by Bun -> **O Framework Full-Stack TypeScript que Você Estava Esperando** +[![npm version](https://badge.fury.io/js/create-fluxstack.svg)](https://badge.fury.io/js/create-fluxstack) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -[![TypeScript](https://img.shields.io/badge/TypeScript-5.9.2-3178C6?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/) -[![Bun](https://img.shields.io/badge/Runtime-Bun%201.2.20-000000?style=flat-square&logo=bun)](https://bun.sh/) -[![React](https://img.shields.io/badge/React-19.1.0-61DAFB?style=flat-square&logo=react&logoColor=black)](https://react.dev/) -[![Elysia](https://img.shields.io/badge/Elysia-1.4.6-8B5CF6?style=flat-square)](https://elysiajs.com/) -[![License](https://img.shields.io/badge/License-MIT-green?style=flat-square)](./LICENSE) +## 🚀 Quick Start -**🔥 Type Safety Automática • ⚡ Zero Configuração • 🚀 Performance Extrema • 🎯 Developer Experience** - -[🚀 **Começar Agora**](#-quick-start) • [📖 **Docs**](./ai-context/) • [💡 **Exemplos**](#-exemplos) • [🎯 **Por Que Escolher?**](#-por-que-fluxstack) +```bash +# Create a new FluxStack app +bunx create-fluxstack my-awesome-app ---- +# Or with npx +npx create-fluxstack my-awesome-app -![FluxStack Demo](https://img.shields.io/badge/🎬-Ver%20Demo%20ao%20Vivo-ff6b6b?style=for-the-badge) +# Navigate and start developing +cd my-awesome-app +bun run dev +``` -
+**That's it!** Your full-stack TypeScript app is ready at: +- **Backend**: http://localhost:3000 +- **Frontend**: http://localhost:5173 +- **API Docs**: http://localhost:3000/swagger -## 🎯 **Por Que FluxStack?** +## ✨ What You Get -### **🔥 O Problema Real** +### 🔥 Modern Tech Stack +- **⚡ Bun Runtime** - 3x faster than Node.js +- **🚀 Elysia.js** - Ultra-fast backend framework +- **⚛️ React 19** - Latest React with modern features +- **🎨 Tailwind CSS v4** - Latest styling framework +- **📦 Vite 7** - Lightning-fast dev server +- **🔒 TypeScript 5** - Full type safety end-to-end -Quantas vezes você já perdeu horas configurando: -- ❌ Múltiplos `package.json` (frontend + backend) -- ❌ APIs sem type safety entre camadas -- ❌ Hot reload que quebra quando você mais precisa -- ❌ Documentação desatualizada da API -- ❌ Builds complexos e lentos -- ❌ Erros TypeScript constantes +### 🛠️ Zero Configuration +- **✅ Hot Reload** - Backend + Frontend coordinated +- **✅ Type Safety** - Eden Treaty for API communication +- **✅ Auto Documentation** - Swagger UI generated +- **✅ Git Ready** - Initialized with first commit +- **✅ Production Ready** - Build scripts included -### **✅ A Solução FluxStack** +## 📁 Project Structure -```typescript -// ✨ Type safety AUTOMÁTICA client ↔ server -const { data, error } = await api.users.post({ - name: "João", // ✅ Autocomplete - email: "joao@teste.com" // ✅ Validação em tempo real -}) - -if (!error) { - console.log(data.user.id) // ✅ Types inferidos automaticamente - console.log(data.success) // ✅ Zero configuração manual -} +``` +my-awesome-app/ +├── core/ # FluxStack framework (don't modify) +├── app/ # Your application code +│ ├── server/ # Backend API routes +│ ├── client/ # Frontend React app +│ └── shared/ # Shared types and utilities +├── package.json # Dependencies and scripts +└── README.md # Project documentation ``` -## 🚀 **Quick Start** (< 2 minutos) +## 🎯 Available Scripts ```bash -# 1. Clone -git clone https://github.com/MarcosBrendonDePaula/FluxStack.git -cd FluxStack +# Development +bun run dev # Start full-stack development +bun run dev:frontend # Frontend only +bun run dev:backend # Backend only -# 2. Uma instalação para TUDO ✨ -bun install +# Production +bun run build # Build for production +bun run start # Start production server -# 3. Start & Magic ✨ -bun run dev +# Utilities +bun run typecheck # Check TypeScript ``` -**🎉 Pronto!** Abra http://localhost:3000 e veja a mágica acontecer. - -> 💡 **FluxStack Integrado**: Frontend e backend rodam no mesmo servidor (porta 3000)! -> 📁 Frontend: `http://localhost:3000/` -> 🔌 API: `http://localhost:3000/api/` -> 📚 Docs: `http://localhost:3000/swagger` - -## ⚡ **Stack Tecnológica** - -
- -| Camada | Tecnologia | Versão | Por Que? | -|--------|------------|---------|----------| -| **Runtime** | Bun | 1.2.20 | 🚀 **3x mais rápido** que Node.js | -| **Backend** | Elysia.js | 1.4.6 | ⚡ **Ultra-performático**, validação automática | -| **Frontend** | React | 19.1.0 | ⚛️ **Concurrent Features**, hooks modernos | -| **Build** | Vite | 7.0.4 | 🔥 **HMR instantâneo**, build otimizado | -| **Language** | TypeScript | 5.9.2 | 🛡️ **100% type-safe** end-to-end | -| **API Client** | Eden Treaty | Native | 🎯 **Inferência automática** de tipos | +## 🔧 Requirements -
+- **Bun** >= 1.0.0 (recommended) +- **Node.js** >= 18.0.0 (fallback) -## 🎬 **Demonstração ao Vivo** +### Install Bun -
- -### **🔧 Backend API (Elysia.js)** -```typescript -// app/server/routes/users.routes.ts -export const usersRoutes = new Elysia({ prefix: "/users" }) - .get("/", () => ({ users: getAllUsers() })) - .post("/", ({ body }) => createUser(body), { - body: t.Object({ - name: t.String(), - email: t.String({ format: "email" }) - }), - response: t.Object({ - success: t.Boolean(), - user: t.Optional(t.Object({ - id: t.Number(), - name: t.String(), - email: t.String(), - createdAt: t.Date() - })) - }) - }) -``` - -### **⚛️ Frontend com Type Safety (Zero config)** -```typescript -// app/client/src/hooks/useUsers.ts -export function useUsers() { - const [users, setUsers] = useState([]) - - const createUser = async (userData) => { - // ✨ Eden Treaty nativo - Type safety automático - const { data, error } = await api.users.post(userData) - - if (!error) { - setUsers(prev => [...prev, data.user]) // ✨ Types inferidos automaticamente! - } - } - - return { users, createUser } -} +```bash +# Install Bun (if not already installed) +curl -fsSL https://bun.sh/install | bash ``` -
+## 🎨 Customization -## 💡 **Exemplos Práticos** +### Environment Variables -
+The generated app uses these environment variables (in `.env`): -### **🌐 Testando a API (cURL)** ```bash -# Health check -curl http://localhost:3000/api/health +NODE_ENV=development +PORT=3000 +HOST=localhost +VITE_PORT=5173 +VITE_API_URL=http://localhost:3000 +``` -# Listar usuários -curl http://localhost:3000/api/users +### Adding Routes -# Criar usuário -curl -X POST http://localhost:3000/api/users \ - -H "Content-Type: application/json" \ - -d '{"name":"João","email":"joao@teste.com"}' +Backend routes in `app/server/routes/`: -# Swagger automático -open http://localhost:3000/swagger -``` +```typescript +// app/server/routes/users.ts +import { Elysia } from 'elysia' -### **⚛️ Component React** -```tsx -function UserList() { - const { users, createUser, loading } = useUsers() - - return ( -
- {users.map(user => ( - {/* ✨ Types! */} - ))} - -
- ) -} +export const userRoutes = new Elysia({ prefix: '/users' }) + .get('/', () => ({ users: [] })) + .post('/', ({ body }) => ({ user: body })) ``` -
+Frontend API calls with type safety: -## 🔧 **Comandos Principais** +```typescript +// app/client/src/components/Users.tsx +import { api } from '../lib/api' -```bash -# Desenvolvimento -bun run dev # 🚀 Full-stack (Backend + Frontend) -bun run dev:clean # 🧹 Output limpo (sem logs HEAD) -bun run dev:backend # 🎯 Backend apenas (porta 3001) -bun run dev:frontend # ⚛️ Frontend Vite standalone (porta 5173) - -# Build & Deploy -bun run build # 📦 Build otimizado para produção -bun run start # 🚀 Servidor de produção -docker-compose up # 🐳 Docker completo - -# Quality & Testing -bun run test # 🧪 Suite de testes -bun run test:ui # 👁️ Interface visual dos testes -bunx tsc --noEmit # 🔍 Verificação TypeScript +const users = await api.users.get() // ✅ Fully typed! ``` -### **🎯 Modos de Desenvolvimento** +## 🚀 Deployment -| Comando | Porta | Descrição | Uso | -|---------|-------|-----------|-----| -| `bun run dev` | **3000** | 🔥 **Integrado** - Frontend + Backend + API | Desenvolvimento completo | -| `bun run dev:backend` | **3001** | 🎯 **Backend apenas** - API + Swagger | Desenvolvimento de API | -| `bun run dev:frontend` | **5173** | ⚛️ **Frontend apenas** - Vite standalone | Desenvolvimento de UI | +### Option 1: Single Server (Recommended) -> 💡 **Dica**: O modo integrado (`dev`) é recomendado para desenvolvimento completo. -> Use os modos separados quando precisar focar em uma camada específica! +```bash +# Build everything +bun run build -## 🏆 **Diferenciais Únicos** +# Start production server +bun run start +``` -### **🎯 Type Safety Automática** -- **Zero config manual**: Eden Treaty infere tipos automaticamente -- **Sincronização em tempo real**: Mudança no server = tipos atualizados no client -- **Autocomplete perfeito**: IntelliSense funcionando 100% +### Option 2: Separate Deploy -### **⚡ Performance Extrema** -- **Bun runtime**: 3x mais rápido que Node.js -- **Hot reload independente**: Backend ≠ Frontend (zero conflitos) -- **Build otimizado**: Vite + esbuild = velocidade máxima +```bash +# Backend +bun run build:backend +bun dist/index.js -### **🔧 Developer Experience** -- **Uma instalação**: `bun install` para todo o projeto -- **Monorepo inteligente**: Compartilhamento natural de código -- **Documentação viva**: Swagger UI sempre atualizado +# Frontend +bun run build:frontend +# Deploy dist/ folder to CDN +``` -### **🚀 Production Ready** -- **Docker otimizado**: Multi-stage builds -- **Environment variables**: Sistema robusto com precedência -- **Error handling**: Tratamento consistente e elegante +## 🤝 Examples -## 📁 **Estrutura do Projeto** +### Basic CRUD API -``` -FluxStack/ -├── 🔒 core/ # Framework (não editar) -│ ├── server/ # Elysia + plugins -│ ├── config/ # Configurações -│ └── build/ # Sistema de build -├── 👨‍💻 app/ # SEU CÓDIGO -│ ├── server/ # Backend (controllers, routes) -│ ├── client/ # Frontend (React + Vite) -│ └── shared/ # Types compartilhados -├── 📖 ai-context/ # Documentação AI -└── 🐳 docker/ # Configurações Docker +```typescript +// app/server/routes/posts.ts +export const postRoutes = new Elysia({ prefix: '/posts' }) + .get('/', () => ({ posts: [] })) + .post('/', ({ body }) => ({ id: 1, ...body })) + .get('/:id', ({ params }) => ({ id: params.id })) ``` -## 🚀 **Deploy em Produção** +### Frontend Integration -### **Docker (Recomendado)** -```bash -# Build e deploy -docker-compose up -d +```typescript +// app/client/src/hooks/usePosts.ts +import { api } from '../lib/api' -# Ou build customizado -docker build -t fluxstack . -docker run -p 3000:3000 fluxstack +export function usePosts() { + return useQuery({ + queryKey: ['posts'], + queryFn: () => api.posts.get() + }) +} ``` -### **Cloud Providers** -```bash -# Vercel, Netlify, Railway, etc. -bun run build -# Deploy da pasta dist/ -``` +## 🛟 Troubleshooting -## 🤝 **Contribuindo** +### Port Already in Use ```bash -# Fork o repositório -git clone https://github.com/SEU-USER/FluxStack.git - -# Crie uma branch -git checkout -b minha-feature +# Kill processes on ports +pkill -f "3000" +pkill -f "5173" +``` -# Implemente e teste -bun run dev -bun run test +### Type Errors -# Commit e PR -git commit -m "feat: minha feature incrível" -git push origin minha-feature +```bash +# Regenerate types +bun run typecheck ``` -## 📊 **Roadmap** +### Environment Issues -- [x] ✅ Eden Treaty nativo com type inference -- [x] ✅ Hot reload independente -- [x] ✅ Monorepo unificado -- [x] ✅ Docker otimizado -- [ ] 🔄 Database layer (Prisma/Drizzle) -- [ ] 🔄 Authentication built-in -- [ ] 🔄 Real-time (WebSockets) -- [ ] 🔄 CLI generator +```bash +# Force development mode +NODE_ENV=development bun run dev +``` -## 📚 **Documentação Completa** +## 📖 Learn More -- **[🚀 Quick Start AI](./ai-context/00-QUICK-START.md)** - 2 minutos para dominar -- **[👨‍💻 Development Patterns](./ai-context/development/patterns.md)** - Melhores práticas -- **[🔧 Eden Treaty Guide](./ai-context/development/eden-treaty-guide.md)** - Type safety automática -- **[💡 CRUD Example](./ai-context/examples/crud-complete.md)** - Exemplo completo -- **[🚨 Troubleshooting](./ai-context/reference/troubleshooting.md)** - Resolução de problemas +- [FluxStack Documentation](https://fluxstack.dev) +- [Bun Runtime](https://bun.sh) +- [Elysia.js](https://elysiajs.com) +- [React 19](https://react.dev) -## 🆘 **Suporte** +## 🐛 Issues & Contributing -- **🐛 Issues**: [GitHub Issues](https://github.com/MarcosBrendonDePaula/FluxStack/issues) -- **💬 Discussões**: [GitHub Discussions](https://github.com/MarcosBrendonDePaula/FluxStack/discussions) -- **📧 Email**: marcos.brendon@exemplo.com +Found a bug? Have a suggestion? +- [GitHub Issues](https://github.com/fluxstack/create-fluxstack/issues) +- [GitHub Discussions](https://github.com/fluxstack/create-fluxstack/discussions) -## 📄 **Licença** +## 📄 License -MIT © [Marcos Brendon de Paula](https://github.com/MarcosBrendonDePaula) +MIT © FluxStack Team --- -
- -**⭐ Se FluxStack te salvou horas de configuração, deixe uma estrela!** - -[![GitHub stars](https://img.shields.io/github/stars/MarcosBrendonDePaula/FluxStack?style=social)](https://github.com/MarcosBrendonDePaula/FluxStack/stargazers) -[![GitHub forks](https://img.shields.io/github/forks/MarcosBrendonDePaula/FluxStack?style=social)](https://github.com/MarcosBrendonDePaula/FluxStack/network/members) - -**🚀 Desenvolvido com ❤️ para a comunidade dev brasileira** - -
\ No newline at end of file +**Happy coding with the divine Bun runtime! ⚡🔥** \ No newline at end of file diff --git a/bun.lock b/bun.lock index 968744a8..fcebac58 100644 --- a/bun.lock +++ b/bun.lock @@ -8,11 +8,14 @@ "@elysiajs/swagger": "^1.3.1", "@types/http-proxy-middleware": "^1.0.0", "@vitejs/plugin-react": "^4.6.0", + "chalk": "^5.3.0", "chokidar": "^4.0.3", + "commander": "^12.1.0", "elysia": "^1.4.6", "http-proxy-middleware": "^3.0.5", "lightningcss": "^1.30.1", "lucide-react": "^0.544.0", + "ora": "^8.1.0", "react": "^19.1.0", "react-dom": "^19.1.0", "vite": "^7.0.4", @@ -385,7 +388,7 @@ "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], - "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], @@ -417,7 +420,7 @@ "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], - "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], "check-error": ["check-error@2.1.1", "", {}, "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw=="], @@ -425,12 +428,18 @@ "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], + "cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="], + + "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="], + "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + "commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], "concurrently": ["concurrently@9.2.1", "", { "dependencies": { "chalk": "4.1.2", "rxjs": "7.8.2", "shell-quote": "1.8.3", "supports-color": "8.1.1", "tree-kill": "1.2.2", "yargs": "17.7.2" }, "bin": { "conc": "dist/bin/concurrently.js", "concurrently": "dist/bin/concurrently.js" } }, "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng=="], @@ -469,7 +478,7 @@ "elysia": ["elysia@1.4.6", "", { "dependencies": { "cookie": "^1.0.2", "exact-mirror": "0.2.2", "fast-decode-uri-component": "^1.0.1" }, "optionalDependencies": { "@sinclair/typebox": ">= 0.34.0 < 1", "openapi-types": ">= 12.0.0" }, "peerDependencies": { "file-type": ">= 20.0.0", "typescript": ">= 5.0.0" } }, "sha512-u2CorXLPs5ZXyWP+tQR+bgka/lJA4vNpB8lDE2w/sTmdaIwoPQmHEL4J3ai6OAlluWR1kfG7T9gO3EYT9D8viQ=="], - "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "emoji-regex": ["emoji-regex@10.5.0", "", {}, "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg=="], "enhanced-resolve": ["enhanced-resolve@5.18.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww=="], @@ -549,6 +558,8 @@ "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + "get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="], + "glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], @@ -593,12 +604,16 @@ "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + "is-interactive": ["is-interactive@2.0.0", "", {}, "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ=="], + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], "is-plain-object": ["is-plain-object@5.0.0", "", {}, "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="], "is-potential-custom-element-name": ["is-potential-custom-element-name@1.0.1", "", {}, "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="], + "is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="], + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], "istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="], @@ -659,6 +674,8 @@ "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], + "log-symbols": ["log-symbols@6.0.0", "", { "dependencies": { "chalk": "^5.3.0", "is-unicode-supported": "^1.3.0" } }, "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw=="], + "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="], "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], @@ -677,6 +694,8 @@ "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="], + "min-indent": ["min-indent@1.0.1", "", {}, "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="], "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], @@ -699,10 +718,14 @@ "nwsapi": ["nwsapi@2.2.22", "", {}, "sha512-ujSMe1OWVn55euT1ihwCI1ZcAaAU3nxUiDwfDQldc51ZXaB9m2AyOn6/jh1BLe2t/G8xd6uKG1UBF2aZJeg2SQ=="], + "onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], + "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], + "ora": ["ora@8.2.0", "", { "dependencies": { "chalk": "^5.3.0", "cli-cursor": "^5.0.0", "cli-spinners": "^2.9.2", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.0.0", "log-symbols": "^6.0.0", "stdin-discarder": "^0.2.2", "string-width": "^7.2.0", "strip-ansi": "^7.1.0" } }, "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw=="], + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], @@ -755,6 +778,8 @@ "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + "restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="], + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], "rollup": ["rollup@4.51.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.51.0", "@rollup/rollup-android-arm64": "4.51.0", "@rollup/rollup-darwin-arm64": "4.51.0", "@rollup/rollup-darwin-x64": "4.51.0", "@rollup/rollup-freebsd-arm64": "4.51.0", "@rollup/rollup-freebsd-x64": "4.51.0", "@rollup/rollup-linux-arm-gnueabihf": "4.51.0", "@rollup/rollup-linux-arm-musleabihf": "4.51.0", "@rollup/rollup-linux-arm64-gnu": "4.51.0", "@rollup/rollup-linux-arm64-musl": "4.51.0", "@rollup/rollup-linux-loong64-gnu": "4.51.0", "@rollup/rollup-linux-ppc64-gnu": "4.51.0", "@rollup/rollup-linux-riscv64-gnu": "4.51.0", "@rollup/rollup-linux-riscv64-musl": "4.51.0", "@rollup/rollup-linux-s390x-gnu": "4.51.0", "@rollup/rollup-linux-x64-gnu": "4.51.0", "@rollup/rollup-linux-x64-musl": "4.51.0", "@rollup/rollup-openharmony-arm64": "4.51.0", "@rollup/rollup-win32-arm64-msvc": "4.51.0", "@rollup/rollup-win32-ia32-msvc": "4.51.0", "@rollup/rollup-win32-x64-msvc": "4.51.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-7cR0XWrdp/UAj2HMY/Y4QQEUjidn3l2AY1wSeZoFjMbD8aOMPoV9wgTFYbrJpPzzvejDEini1h3CiUP8wLzxQA=="], @@ -791,11 +816,13 @@ "std-env": ["std-env@3.9.0", "", {}, "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw=="], - "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "stdin-discarder": ["stdin-discarder@0.2.2", "", {}, "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ=="], + + "string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -929,8 +956,6 @@ "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], - "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], - "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], "@scalar/themes/@scalar/types": ["@scalar/types@0.1.7", "", { "dependencies": { "@scalar/openapi-types": "0.2.0", "@unhead/schema": "^1.11.11", "nanoid": "^5.1.5", "type-fest": "^4.20.0", "zod": "^3.23.8" } }, "sha512-irIDYzTQG2KLvFbuTI8k2Pz/R4JR+zUUSykVTbEMatkzMmVFnn1VzNSMlODbadycwZunbnL2tA27AXed9URVjw=="], @@ -955,7 +980,13 @@ "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "concurrently/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "eslint/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], @@ -963,18 +994,36 @@ "istanbul-lib-report/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "log-symbols/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="], + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "pretty-format/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "test-exclude/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "wrap-ansi/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], - "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], - "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], "@scalar/themes/@scalar/types/@scalar/openapi-types": ["@scalar/openapi-types@0.2.0", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-waiKk12cRCqyUCWTOX0K1WEVX46+hVUK+zRPzAahDJ7G0TApvbNkuy5wx7aoUyEk++HHde0XuQnshXnt8jsddA=="], @@ -983,8 +1032,32 @@ "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "cliui/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "concurrently/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "eslint/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "test-exclude/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "wrap-ansi/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], } } diff --git a/create-fluxstack.ts b/create-fluxstack.ts new file mode 100644 index 00000000..00c4638c --- /dev/null +++ b/create-fluxstack.ts @@ -0,0 +1,249 @@ +#!/usr/bin/env bun + +import { program } from 'commander' +import { resolve, join } from 'path' +import { existsSync, mkdirSync, cpSync, writeFileSync, readFileSync } from 'fs' +import chalk from 'chalk' +import ora from 'ora' + +const logo = ` +⚡ ███████ ██ ██ ██ ██ ██ ███████ ████████ █████ ██████ ██ ██ + ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ + █████ ██ ██ ██ ███ ███████ ██ ███████ ██ █████ + ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ + ██ ███████ ██████ ██ ██ ███████ ██ ██ ██ ██████ ██ ██ + +${chalk.cyan('💫 Powered by Bun - The Divine Runtime ⚡')} +${chalk.gray('Creates FluxStack apps by copying the working framework')} +` + +program + .name('create-fluxstack') + .description('⚡ Create FluxStack apps with zero configuration') + .version('1.0.0') + .argument('[project-name]', 'Name of the project to create') + .option('--no-install', 'Skip dependency installation') + .option('--no-git', 'Skip git initialization') + .action(async (projectName, options) => { + console.clear() + console.log(chalk.magenta(logo)) + + if (!projectName || projectName.trim().length === 0) { + console.log(chalk.red('❌ Project name is required')) + console.log(chalk.gray('Usage: ./create-fluxstack.ts my-app')) + process.exit(1) + } + + const currentDir = import.meta.dir + const projectPath = resolve(projectName) + + // Check if directory already exists + if (existsSync(projectPath)) { + console.log(chalk.red(`❌ Directory ${projectName} already exists`)) + process.exit(1) + } + + console.log(chalk.cyan(`\\n🚀 Creating FluxStack project: ${chalk.bold(projectName)}`)) + console.log(chalk.gray(`📁 Location: ${projectPath}`)) + + // Create project directory + const spinner = ora('Creating project structure...').start() + + try { + mkdirSync(projectPath, { recursive: true }) + + // Copy only essential FluxStack files (not node_modules, not test apps, etc.) + const frameworkDir = currentDir // Use current directory (framework root) + const filesToCopy = [ + 'core', + 'app', + 'ai-context', // ✅ CRITICAL: Copy AI documentation for users + 'bun.lock', // ✅ CRITICAL: Copy lockfile to maintain working versions + 'tsconfig.json', + 'vite.config.ts', + '.env.example', // ✅ Use .env.example as template + 'CLAUDE.md', // ✅ Project instructions for AI assistants + 'README.md' + ] + + for (const file of filesToCopy) { + const sourcePath = join(frameworkDir, file) + const destPath = join(projectPath, file) + + if (existsSync(sourcePath)) { + cpSync(sourcePath, destPath, { recursive: true }) + } + } + + // Create package.json from template + const packageJsonPath = join(projectPath, 'package.json') + const templatePath = join(import.meta.dir, 'package-template.json') + + if (existsSync(templatePath)) { + const templateContent = readFileSync(templatePath, 'utf-8') + const packageTemplate = templateContent.replace(/PROJECT_NAME/g, projectName) + writeFileSync(packageJsonPath, packageTemplate) + } else { + // Fallback template if package-template.json doesn't exist + const fallbackPackageJson = { + "name": projectName, + "version": "1.0.0", + "description": `${projectName} - FluxStack application`, + "keywords": ["fluxstack", "bun", "typescript", "full-stack", "elysia", "react", "vite"], + "author": "Your Name", + "license": "MIT", + "type": "module", + "scripts": { + "dev": "bun core/cli/index.ts dev", + "dev:clean": "bun run-clean.ts", + "dev:backend": "bun core/cli/index.ts dev:backend", + "dev:frontend": "bun core/cli/index.ts dev:frontend", + "build": "bun core/cli/index.ts build", + "build:backend": "bun core/cli/index.ts build:backend", + "build:frontend": "bun core/cli/index.ts build:frontend", + "start": "NODE_ENV=production bun app/server/index.ts", + "typecheck": "bunx tsc --noEmit" + } + } + writeFileSync(packageJsonPath, JSON.stringify(fallbackPackageJson, null, 2)) + } + + // Create .env from .env.example and set development mode + const envExamplePath = join(projectPath, '.env.example') + const envPath = join(projectPath, '.env') + if (existsSync(envExamplePath)) { + const envExampleContent = readFileSync(envExamplePath, 'utf-8') + const devEnvContent = envExampleContent.replace( + 'NODE_ENV=production', + 'NODE_ENV=development' + ) + writeFileSync(envPath, devEnvContent) + } + + // Customize README.md + const readmePath = join(projectPath, 'README.md') + if (existsSync(readmePath)) { + const readmeContent = `# ${projectName} + +⚡ **FluxStack Application** - Modern full-stack TypeScript framework + +## 🚀 Getting Started + +\`\`\`bash +# Start development +bun run dev + +# Build for production +bun run build + +# Start production server +bun run start +\`\`\` + +## 📁 Project Structure + +\`\`\` +${projectName}/ +├── core/ # FluxStack framework (don't modify) +├── app/ # Your application code +│ ├── server/ # Backend API routes +│ ├── client/ # Frontend React app +│ └── shared/ # Shared types and utilities +└── package.json +\`\`\` + +## 🔥 Features + +- **⚡ Bun Runtime** - 3x faster than Node.js +- **🔒 Full Type Safety** - Eden Treaty + TypeScript +- **🎨 Modern UI** - React 19 + Tailwind CSS v4 +- **📋 Auto Documentation** - Swagger UI generated +- **🔄 Hot Reload** - Backend + Frontend + +## 📖 Learn More + +Visit the [FluxStack Documentation](https://fluxstack.dev) to learn more! + +--- + +Built with ❤️ using FluxStack +` + writeFileSync(readmePath, readmeContent) + } + + spinner.succeed('✅ Project structure created!') + + // Install dependencies with Bun (THE DIVINE RUNTIME) + if (options.install) { + const installSpinner = ora('📦 Installing dependencies with Bun...').start() + + try { + const proc = Bun.spawn(['bun', 'install'], { + cwd: projectPath, + stdio: ['ignore', 'pipe', 'pipe'] + }) + + await proc.exited + + if (proc.exitCode === 0) { + installSpinner.succeed('✅ Dependencies installed!') + } else { + installSpinner.fail('❌ Failed to install dependencies') + console.log(chalk.gray('You can install them manually with: bun install')) + } + } catch (error) { + installSpinner.fail('❌ Failed to install dependencies') + console.log(chalk.gray('You can install them manually with: bun install')) + } + } + + // Initialize git + if (options.git) { + const gitSpinner = ora('📝 Initializing git repository...').start() + + try { + const initProc = Bun.spawn(['git', 'init'], { + cwd: projectPath, + stdio: ['ignore', 'pipe', 'pipe'] + }) + await initProc.exited + + // Create initial commit + const addProc = Bun.spawn(['git', 'add', '.'], { + cwd: projectPath, + stdio: ['ignore', 'pipe', 'pipe'] + }) + await addProc.exited + + const commitProc = Bun.spawn(['git', 'commit', '-m', `feat: initial ${projectName} with FluxStack`], { + cwd: projectPath, + stdio: ['ignore', 'pipe', 'pipe'] + }) + await commitProc.exited + + gitSpinner.succeed('✅ Git repository initialized!') + } catch (error) { + gitSpinner.fail('❌ Failed to initialize git') + console.log(chalk.gray('You can initialize it manually with: git init')) + } + } + + // Success message + console.log(chalk.green('\\n🎉 Project created successfully!')) + console.log(chalk.cyan('\\nNext steps:')) + console.log(chalk.white(` cd ${projectName}`)) + if (!options.install) { + console.log(chalk.white(` bun install`)) + } + console.log(chalk.white(` bun run dev`)) + console.log(chalk.magenta('\\nHappy coding with the divine Bun runtime! ⚡🔥')) + console.log(chalk.gray('\\nVisit http://localhost:3000 when ready!')) + + } catch (error) { + spinner.fail('❌ Failed to create project') + console.error(error) + process.exit(1) + } + }) + +program.parse() \ No newline at end of file diff --git a/create-test-app.ts b/create-test-app.ts new file mode 100644 index 00000000..e35077de --- /dev/null +++ b/create-test-app.ts @@ -0,0 +1,156 @@ +#!/usr/bin/env bun + +/** + * Script temporário para testar criação de aplicação FluxStack + * Simula o comportamento do create-fluxstack CLI + */ + +import { promises as fs } from 'fs'; +import path from 'path'; + +interface ProjectOptions { + name: string; + template: 'basic' | 'minimal' | 'full'; + targetDir?: string; +} + +async function createTestApp(options: ProjectOptions) { + const { name, template } = options; + const projectPath = path.resolve('test-apps', name); + + console.log(`🚀 Creating FluxStack app: ${name}`); + console.log(`📁 Location: ${projectPath}`); + console.log(`📋 Template: ${template}`); + console.log(); + + // Check if directory already exists + try { + await fs.access(projectPath); + console.log(`❌ Directory ${name} already exists`); + return; + } catch (error: any) { + if (error.code !== 'ENOENT') { + throw error; + } + } + + // Create project directory + await fs.mkdir(projectPath, { recursive: true }); + + // Get template path + const templatePath = path.resolve('framework-distribution', 'create-fluxstack', 'templates', template); + + // Copy template files + await copyDirectory(templatePath, projectPath); + + // Process template files (replace placeholders) + await processTemplateFiles(projectPath, { + PROJECT_NAME: name, + PROJECT_DESCRIPTION: `A FluxStack application named ${name}`, + PROJECT_NAME_KEBAB: name, + PROJECT_NAME_CAMEL: toCamelCase(name), + PROJECT_NAME_PASCAL: toPascalCase(name) + }); + + console.log('✅ Project created successfully!'); + console.log(); + console.log('Next steps:'); + console.log(` cd test-apps/${name}`); + console.log(' bun install'); + console.log(' bun run dev'); + console.log(); +} + +async function copyDirectory(src: string, dest: string, exclude: string[] = []) { + await fs.mkdir(dest, { recursive: true }); + + const entries = await fs.readdir(src, { withFileTypes: true }); + + for (const entry of entries) { + if (exclude.includes(entry.name)) continue; + + const srcPath = path.join(src, entry.name); + const destPath = path.join(dest, entry.name); + + if (entry.isDirectory()) { + await copyDirectory(srcPath, destPath, exclude); + } else { + const content = await fs.readFile(srcPath, 'utf-8'); + await fs.writeFile(destPath, content, 'utf-8'); + } + } +} + +async function processTemplateFiles( + projectPath: string, + replacements: Record +) { + const files = await getAllFiles(projectPath); + + for (const file of files) { + // Skip binary files + if (isBinaryFile(file)) continue; + + let content = await fs.readFile(file, 'utf-8'); + + // Replace placeholders + for (const [key, value] of Object.entries(replacements)) { + const regex = new RegExp(`{{${key}}}`, 'g'); + content = content.replace(regex, value); + } + + await fs.writeFile(file, content, 'utf-8'); + } +} + +async function getAllFiles(dirPath: string): Promise { + const files: string[] = []; + + const items = await fs.readdir(dirPath, { withFileTypes: true }); + + for (const item of items) { + const fullPath = path.join(dirPath, item.name); + + if (item.isDirectory()) { + files.push(...await getAllFiles(fullPath)); + } else { + files.push(fullPath); + } + } + + return files; +} + +function isBinaryFile(filePath: string): boolean { + const binaryExtensions = [ + '.png', '.jpg', '.jpeg', '.gif', '.ico', '.svg', + '.woff', '.woff2', '.ttf', '.eot', + '.zip', '.tar', '.gz', '.rar' + ]; + + const ext = path.extname(filePath).toLowerCase(); + return binaryExtensions.includes(ext); +} + +function toCamelCase(str: string): string { + return str + .replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : '') + .replace(/^[A-Z]/, char => char.toLowerCase()); +} + +function toPascalCase(str: string): string { + const camelCase = toCamelCase(str); + return camelCase.charAt(0).toUpperCase() + camelCase.slice(1); +} + +// Run the script +const projectName = process.argv[2] || 'test-todo-app'; +const template = (process.argv[3] as 'basic' | 'minimal' | 'full') || 'basic'; + +createTestApp({ + name: projectName, + template +}).catch(error => { + console.error('❌ Error creating project:', error); + process.exit(1); +}); \ No newline at end of file diff --git a/docs/dynamic-environment-variables.md b/docs/dynamic-environment-variables.md deleted file mode 100644 index b8305c4b..00000000 --- a/docs/dynamic-environment-variables.md +++ /dev/null @@ -1,380 +0,0 @@ -# 🔄 Dynamic Environment Variables for FluxStack - -## 🚨 **Problema Resolvido** - -O **Bun build** fixa valores de `process.env` durante a compilação, impossibilitando mudanças de environment variables em produção sem rebuild. - -### ❌ **Problema Original** -```typescript -// Durante build, Bun converte isto: -const port = process.env.PORT || 3000 - -// Em isto (valor fixo): -const port = "8080" || 3000 // Fixado no build! -``` - -### ✅ **Solução FluxStack** -```typescript -import { env } from '@/core/utils/env-runtime' - -// Sempre dinâmico, mesmo após build: -const port = env.num('PORT', 3000) // 🚀 Funciona em runtime! -``` - ---- - -## 🛠️ **Como Usar** - -### **1. Import Básico** -```typescript -import { env } from '@/core/utils/env-runtime' - -// Métodos disponíveis: -const port = env.num('PORT', 3000) // number -const host = env.get('HOST', 'localhost') // string -const debug = env.bool('DEBUG', false) // boolean -const origins = env.array('CORS_ORIGINS') // string[] -const hasDb = env.has('DATABASE_URL') // boolean -``` - -### **2. Propriedades Shorthand** -```typescript -// Acesso direto para vars comuns: -console.log(env.PORT) // number -console.log(env.NODE_ENV) // string -console.log(env.DATABASE_URL) // string | undefined -console.log(env.CORS_ORIGINS) // string[] -``` - -### **3. Configuração de Servidor** -```typescript -import { createRuntimeConfig } from '@/core/config/runtime-config' - -const config = createRuntimeConfig({ - server: { - port: env.num('PORT', 3000), - host: env.get('HOST', 'localhost') - } -}) - -const app = new FluxStackFramework(config) -``` - -### **4. Diferentes Ambientes** -```typescript -import { runtimeConfig } from '@/core/config/runtime-config' - -// Auto-detect do ambiente: -const config = runtimeConfig.auto() - -// Ou específico: -const devConfig = runtimeConfig.development() -const prodConfig = runtimeConfig.production() -const testConfig = runtimeConfig.test() -``` - ---- - -## 🔧 **Migração do Código Existente** - -### **Antes (Fixado pelo Bun)** -```typescript -// ❌ Será fixado durante build -const oldConfig = { - port: parseInt(process.env.PORT || '3000'), - dbUrl: process.env.DATABASE_URL, - debug: process.env.DEBUG === 'true', - corsOrigins: process.env.CORS_ORIGINS?.split(',') || ['*'], - enableMonitoring: process.env.MONITORING_ENABLED === 'true' -} -``` - -### **Depois (Dinâmico)** -```typescript -// ✅ Sempre dinâmico, mesmo após build -import { env } from '@/core/utils/env-runtime' - -const newConfig = { - port: env.num('PORT', 3000), - dbUrl: env.get('DATABASE_URL'), - debug: env.bool('DEBUG', false), - corsOrigins: env.array('CORS_ORIGINS', ['*']), - enableMonitoring: env.bool('MONITORING_ENABLED', false) -} -``` - ---- - -## 🏗️ **Configuração Avançada** - -### **1. Namespaces de Environment** -```typescript -import { createEnvNamespace } from '@/core/utils/env-runtime' - -// Criar loaders especializados -const dbEnv = createEnvNamespace('DATABASE_') -const redisEnv = createEnvNamespace('REDIS_') -const awsEnv = createEnvNamespace('AWS_') - -// Uso: -const dbConfig = { - url: dbEnv.get('URL'), // DATABASE_URL - host: dbEnv.get('HOST'), // DATABASE_HOST - port: dbEnv.getNumber('PORT') // DATABASE_PORT -} -``` - -### **2. Validação de Environment** -```typescript -import { envValidation } from '@/core/utils/env-runtime' - -// Validar vars obrigatórias -envValidation.require(['NODE_ENV', 'DATABASE_URL']) - -// Validar formato -envValidation.validate('DATABASE_URL', - (url) => url.includes('://'), - 'DATABASE_URL deve ser uma URL válida' -) -``` - -### **3. Configuração Condicional** -```typescript -import { env } from '@/core/utils/env-runtime' - -export function createServerConfig() { - const config = { - port: env.num('PORT', 3000), - - // Database apenas se configurado - ...(env.has('DATABASE_URL') && { - database: { - url: env.get('DATABASE_URL'), - ssl: env.bool('DB_SSL', env.get('NODE_ENV') === 'production') - } - }), - - // Features baseadas no ambiente - features: { - swagger: env.bool('ENABLE_SWAGGER', env.get('NODE_ENV') !== 'production'), - monitoring: env.bool('ENABLE_MONITORING', env.get('NODE_ENV') === 'production') - } - } - - return config -} -``` - ---- - -## 🚀 **Integração com FluxStack** - -### **1. Servidor com Env Dinâmico** -```typescript -import { FluxStackFramework } from '@/core/framework/server' -import { createRuntimeConfig } from '@/core/config/runtime-config' -import { env } from '@/core/utils/env-runtime' - -export async function startServer() { - // Configuração dinâmica - const config = createRuntimeConfig() - - // Framework com env dinâmico - const app = new FluxStackFramework(config) - - // Plugins condicionais - if (env.bool('ENABLE_SWAGGER', true)) { - app.use(swaggerPlugin) - } - - if (env.bool('ENABLE_MONITORING', false)) { - app.use(monitoringPlugin) - } - - await app.listen() - - console.log(`🚀 Server running on port ${env.num('PORT', 3000)}`) -} -``` - -### **2. Build Configuration** -```typescript -// No fluxstack.config.ts -import { env } from '@/core/utils/env-runtime' - -export const config = { - app: { - name: env.get('FLUXSTACK_APP_NAME', 'my-app'), - version: env.get('FLUXSTACK_APP_VERSION', '1.0.0') - }, - - server: { - port: env.num('PORT', 3000), - host: env.get('HOST', 'localhost'), - cors: { - origins: env.array('CORS_ORIGINS', ['*']) - } - }, - - build: { - target: env.get('BUILD_TARGET', 'bun'), - outDir: env.get('BUILD_OUTDIR', 'dist'), - optimization: { - minify: env.bool('BUILD_MINIFY', env.get('NODE_ENV') === 'production') - } - } -} -``` - ---- - -## 🧪 **Testando com Env Dinâmico** - -### **1. Configuração de Teste** -```typescript -import { runtimeConfig } from '@/core/config/runtime-config' - -// Configuração isolada para testes -const testConfig = runtimeConfig.test() - -// Ou com overrides específicos -const config = runtimeConfig.auto({ - server: { port: 0 }, // Porta aleatória - database: { url: 'sqlite://memory:' } -}) -``` - -### **2. Mock de Environment Variables** -```typescript -import { withTestEnv } from '@/examples/dynamic-env-usage' - -test('server configuration with custom env', () => { - withTestEnv({ - 'PORT': '9000', - 'NODE_ENV': 'test', - 'DEBUG': 'true' - }, () => { - const config = createServerConfig() - expect(config.port).toBe(9000) - expect(config.debug).toBe(true) - }) -}) -``` - ---- - -## 📦 **Deploy e Produção** - -### **1. Docker com Env Dinâmico** -```dockerfile -# Dockerfile -FROM oven/bun:1.1-alpine - -WORKDIR /app -COPY . . - -# Build com env dinâmico funcionando -RUN bun run build - -# Environment variables não fixadas no build -ENV NODE_ENV=production -ENV PORT=3000 - -CMD ["bun", "run", "dist/index.js"] -``` - -### **2. Docker Compose** -```yaml -# docker-compose.yml -version: '3.8' -services: - app: - build: . - ports: - - "${PORT:-3000}:${PORT:-3000}" - environment: - - NODE_ENV=production - - PORT=${PORT:-3000} - - DATABASE_URL=${DATABASE_URL} - - JWT_SECRET=${JWT_SECRET} - - CORS_ORIGINS=${CORS_ORIGINS:-*} - - ENABLE_MONITORING=${ENABLE_MONITORING:-true} -``` - -### **3. Deploy com Variáveis Dinâmicas** -```bash -# Build uma vez -bun run build - -# Deploy em diferentes ambientes (sem rebuild!) -NODE_ENV=staging PORT=4000 bun run dist/index.js -NODE_ENV=production PORT=8080 DATABASE_URL=postgres://... bun run dist/index.js -``` - ---- - -## ⚡ **Performance e Compatibilidade** - -### **Overhead** -- **Mínimo**: Apenas uma verificação extra por acesso -- **Cache**: Valores são cached dentro da mesma execução -- **Bun.env**: Usa Bun.env quando disponível (mais rápido) - -### **Compatibilidade** -- ✅ **Bun runtime**: Usa `Bun.env` otimizado -- ✅ **Node.js**: Fallback para `process.env` -- ✅ **Build tools**: Resistente a otimizações -- ✅ **Testing**: Funciona com mocks - -### **Fallbacks** -1. `Bun.env` (mais rápido no Bun) -2. `process.env` (Node.js/fallback) -3. `eval('process')` (edge cases) - ---- - -## 🔍 **Debugging** - -### **Ver Todas as Environment Variables** -```typescript -import { env } from '@/core/utils/env-runtime' - -// Listar todas as env vars -console.log(env.all()) - -// Verificar se existe -if (env.has('DATABASE_URL')) { - console.log('Database configured') -} - -// Debug de configuração -console.log('🔧 Current config:') -console.log(` NODE_ENV: ${env.get('NODE_ENV')}`) -console.log(` PORT: ${env.num('PORT', 3000)}`) -console.log(` DEBUG: ${env.bool('DEBUG')}`) -``` - ---- - -## 📋 **Checklist de Migração** - -- [ ] Substituir `process.env.VAR` por `env.get('VAR')` -- [ ] Usar `env.num()`, `env.bool()`, `env.array()` conforme tipo -- [ ] Atualizar configuração do FluxStack -- [ ] Testar em desenvolvimento -- [ ] Testar build e produção -- [ ] Verificar Docker/deploy -- [ ] Documentar env vars específicas do projeto - ---- - -## 🎯 **Benefícios** - -✅ **Env vars dinâmicas** mesmo após Bun build -✅ **Deploy flexível** sem rebuild -✅ **Type-safe** com conversão automática -✅ **Validação** de env vars obrigatórias -✅ **Namespace** para organização -✅ **Compatibilidade** com Node.js e Bun -✅ **Performance** otimizada -✅ **Testing** friendly \ No newline at end of file diff --git a/examples/dynamic-env-usage.ts b/examples/dynamic-env-usage.ts deleted file mode 100644 index 12c530e3..00000000 --- a/examples/dynamic-env-usage.ts +++ /dev/null @@ -1,283 +0,0 @@ -/** - * Exemplos de como usar o sistema de Environment Variables dinâmico - * Solução para o problema do Bun build fixar valores de process.env - */ - -// ======================================== -// 1. IMPORT DO SISTEMA DINÂMICO -// ======================================== - -import { env, runtimeEnv, envValidation } from '../core/utils/env-runtime' -import { createRuntimeConfig, runtimeConfig, configHelpers } from '../core/config/runtime-config' -import { dynamicEnvironmentProcessor } from '../core/config/env-dynamic' - -// ======================================== -// 2. USO BÁSICO - Substituir process.env -// ======================================== - -// ❌ ANTES (fixado pelo Bun build): -// const port = process.env.PORT || 3000 -// const dbUrl = process.env.DATABASE_URL - -// ✅ DEPOIS (dinâmico em runtime): -const port = env.num('PORT', 3000) -const dbUrl = env.get('DATABASE_URL') -const isDebug = env.bool('DEBUG', false) -const corsOrigins = env.array('CORS_ORIGINS', ['*']) - -console.log('🚀 Server will start on port:', port) // Valor dinâmico! - -// ======================================== -// 3. CONFIGURAÇÃO DE SERVIDOR DINÂMICA -// ======================================== - -export function createDynamicServer() { - // Configuração que funciona em produção sem rebuild - const serverConfig = { - port: env.num('PORT', 3000), - host: env.get('HOST', 'localhost'), - - // Database dinâmico - database: { - url: env.get('DATABASE_URL'), - maxConnections: env.num('DB_MAX_CONNECTIONS', 10), - ssl: env.bool('DB_SSL', env.get('NODE_ENV') === 'production') - }, - - // CORS dinâmico - cors: { - origins: env.array('CORS_ORIGINS', ['*']), - credentials: env.bool('CORS_CREDENTIALS', false) - }, - - // JWT dinâmico - jwt: { - secret: env.get('JWT_SECRET') || generateSecret(), - expiresIn: env.get('JWT_EXPIRES_IN', '24h') - }, - - // Features dinâmicas - features: { - monitoring: env.bool('ENABLE_MONITORING', env.get('NODE_ENV') === 'production'), - metrics: env.bool('ENABLE_METRICS', false), - swagger: env.bool('ENABLE_SWAGGER', env.get('NODE_ENV') !== 'production') - } - } - - return serverConfig -} - -// ======================================== -// 4. FLUXSTACK COM ENV DINÂMICO -// ======================================== - -import { FluxStackFramework } from '../core/framework/server' - -export function createFluxStackWithDynamicEnv() { - // Usar configuração runtime dinâmica - const config = createRuntimeConfig({ - // Overrides específicos - server: { - port: env.num('PORT', 3000), - host: env.get('HOST', 'localhost'), - } - }) - - const app = new FluxStackFramework(config) - - // Configurações que mudam em runtime - if (env.bool('ENABLE_SWAGGER', true)) { - // Swagger só se habilitado - } - - if (env.bool('ENABLE_MONITORING', false)) { - // Monitoring só se habilitado - } - - return app -} - -// ======================================== -// 5. DIFERENTES AMBIENTES -// ======================================== - -export function createEnvironmentSpecificConfig() { - const environment = env.get('NODE_ENV', 'development') - - switch (environment) { - case 'development': - return runtimeConfig.development() - - case 'production': - return runtimeConfig.production() - - case 'test': - return runtimeConfig.test() - - default: - return runtimeConfig.auto() - } -} - -// ======================================== -// 6. VALIDAÇÃO DE ENV VARS -// ======================================== - -export function validateEnvironment() { - // Validar vars obrigatórias - envValidation.require(['NODE_ENV']) - - // Se production, validar mais vars - if (env.get('NODE_ENV') === 'production') { - envValidation.require([ - 'DATABASE_URL', - 'JWT_SECRET' - ]) - - // Validar formato - envValidation.validate('DATABASE_URL', - (url) => url.includes('://'), - 'DATABASE_URL deve ser uma URL válida' - ) - } -} - -// ======================================== -// 7. CONFIGURAÇÃO POR NAMESPACE -// ======================================== - -import { createEnvNamespace } from '../core/utils/env-runtime' - -// Criar loaders especializados -const dbEnv = createEnvNamespace('DATABASE_') -const redisEnv = createEnvNamespace('REDIS_') -const awsEnv = createEnvNamespace('AWS_') - -export function createDatabaseConfig() { - return { - url: dbEnv.get('URL'), // DATABASE_URL - host: dbEnv.get('HOST'), // DATABASE_HOST - port: dbEnv.getNumber('PORT'), // DATABASE_PORT - ssl: dbEnv.getBoolean('SSL'), // DATABASE_SSL - } -} - -export function createRedisConfig() { - return { - url: redisEnv.get('URL'), // REDIS_URL - host: redisEnv.get('HOST'), // REDIS_HOST - port: redisEnv.getNumber('PORT'), // REDIS_PORT - } -} - -// ======================================== -// 8. CONFIGURAÇÃO HELPERS -// ======================================== - -export function getAppConfig() { - return { - // Server config dinâmico - server: configHelpers.getServerConfig(), - - // Client config dinâmico - client: configHelpers.getClientConfig(), - - // Database com validação - database: configHelpers.getDatabaseUrl(), - - // CORS com defaults inteligentes - cors: configHelpers.getCorsOrigins() - } -} - -// ======================================== -// 9. EXEMPLO COMPLETO DE USO -// ======================================== - -export async function startFluxStackServer() { - console.log('🔧 Validating environment...') - validateEnvironment() - - console.log('⚙️ Loading dynamic configuration...') - const config = createEnvironmentSpecificConfig() - - console.log('🚀 Starting FluxStack with dynamic env...') - const app = new FluxStackFramework(config) - - // Log das configurações atuais (valores dinâmicos!) - console.log('📊 Configuration loaded:') - console.log(` Environment: ${env.get('NODE_ENV')}`) - console.log(` Port: ${env.num('PORT', 3000)}`) - console.log(` Database: ${env.get('DATABASE_URL') ? '✅ Connected' : '❌ Not configured'}`) - console.log(` Monitoring: ${env.bool('ENABLE_MONITORING') ? '✅ Enabled' : '❌ Disabled'}`) - - await app.listen() - - console.log('✅ Server started with dynamic environment variables!') -} - -// ======================================== -// 10. MIGRANDO CÓDIGO EXISTENTE -// ======================================== - -// ❌ Código antigo que será fixado pelo Bun: -export const oldConfig = { - port: parseInt(process.env.PORT || '3000'), - dbUrl: process.env.DATABASE_URL, - debug: process.env.DEBUG === 'true' -} - -// ✅ Código novo que funciona dinamicamente: -export const newConfig = { - port: env.num('PORT', 3000), - dbUrl: env.get('DATABASE_URL'), - debug: env.bool('DEBUG', false) -} - -// ======================================== -// 11. TESTES COM ENV DINÂMICO -// ======================================== - -export function createTestConfig() { - // Configuração para testes que não interfere com env vars reais - return runtimeConfig.test() -} - -// Helper para simular env vars em testes -export function withTestEnv(envVars: Record, fn: () => void) { - const original = { ...runtimeEnv.all() } - - // Simular env vars - Object.assign(process.env, envVars) - - try { - fn() - } finally { - // Restaurar env original - Object.keys(envVars).forEach(key => { - if (original[key] !== undefined) { - process.env[key] = original[key] - } else { - delete process.env[key] - } - }) - } -} - -// Função helper para gerar secret se não existir -function generateSecret(): string { - console.warn('⚠️ JWT_SECRET not found, generating random secret for development') - return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) -} - -// ======================================== -// 12. EXPORT DEFAULT -// ======================================== - -export default { - createDynamicServer, - createFluxStackWithDynamicEnv, - validateEnvironment, - startFluxStackServer, - getAppConfig -} \ No newline at end of file diff --git a/examples/hybrid-env-strategy.ts b/examples/hybrid-env-strategy.ts deleted file mode 100644 index 35825609..00000000 --- a/examples/hybrid-env-strategy.ts +++ /dev/null @@ -1,212 +0,0 @@ -/** - * Estratégia Híbrida: Env Fixado + Env Dinâmico - * Use o melhor de cada abordagem conforme necessário - */ - -import { env } from '@/core/utils/env-runtime' - -// ======================================== -// CONFIGURAÇÕES FIXADAS (Build-time) -// ======================================== -// Use para valores que nunca mudam ou precisam de máxima performance - -// App metadata - fixado é OK -const APP_NAME = process.env.FLUXSTACK_APP_NAME || 'FluxStack' -const APP_VERSION = process.env.FLUXSTACK_APP_VERSION || '1.0.0' - -// Feature flags - fixado é OK -const ENABLE_SWAGGER = process.env.ENABLE_SWAGGER !== 'false' -const ENABLE_CORS = process.env.ENABLE_CORS !== 'false' - -// Build configuration - fixado é ideal -const BUILD_TARGET = process.env.BUILD_TARGET || 'bun' -const CLIENT_OUTDIR = process.env.CLIENT_OUTDIR || 'dist/client' - -// ======================================== -// CONFIGURAÇÕES DINÂMICAS (Runtime) -// ======================================== -// Use para valores que precisam mudar em diferentes deploys - -// Server config - deve ser dinâmico -const getServerConfig = () => ({ - port: env.num('PORT', 3000), // 🔄 Dinâmico - host: env.get('HOST', 'localhost'), // 🔄 Dinâmico - apiPrefix: env.get('API_PREFIX', '/api') -}) - -// Database - deve ser dinâmico -const getDatabaseConfig = () => ({ - url: env.get('DATABASE_URL'), // 🔄 Dinâmico - maxConnections: env.num('DB_MAX_CONNECTIONS', 10), - ssl: env.bool('DB_SSL', env.get('NODE_ENV') === 'production') -}) - -// Secrets - deve ser dinâmico -const getSecrets = () => ({ - jwtSecret: env.get('JWT_SECRET'), // 🔄 Dinâmico - apiKey: env.get('API_KEY'), - encryptionKey: env.get('ENCRYPTION_KEY') -}) - -// Environment specific - dinâmico -const getEnvironmentConfig = () => ({ - nodeEnv: env.get('NODE_ENV', 'development'), // 🔄 Dinâmico - logLevel: env.get('LOG_LEVEL', 'info'), - debug: env.bool('DEBUG', false) -}) - -// ======================================== -// CONFIGURAÇÃO HÍBRIDA -// ======================================== - -export const hybridConfig = { - // Fixado no build (performance máxima) - app: { - name: APP_NAME, // ⚡ Fixado - version: APP_VERSION, // ⚡ Fixado - enableSwagger: ENABLE_SWAGGER, // ⚡ Fixado - enableCors: ENABLE_CORS // ⚡ Fixado - }, - - build: { - target: BUILD_TARGET, // ⚡ Fixado - clientOutDir: CLIENT_OUTDIR // ⚡ Fixado - }, - - // Dinâmico no runtime (flexibilidade máxima) - runtime: { - server: getServerConfig(), // 🔄 Dinâmico - database: getDatabaseConfig(), // 🔄 Dinâmico - secrets: getSecrets(), // 🔄 Dinâmico - environment: getEnvironmentConfig() // 🔄 Dinâmico - } -} - -// ======================================== -// EXEMPLO DE USO PRÁTICO -// ======================================== - -export function createHybridServer() { - console.log(`🚀 Starting ${hybridConfig.app.name} v${hybridConfig.app.version}`) - - const { server, database, environment } = hybridConfig.runtime - - console.log(`📊 Environment: ${environment.nodeEnv}`) - console.log(`🌐 Server: ${server.host}:${server.port}`) - console.log(`💾 Database: ${database.url ? '✅ Connected' : '❌ Not configured'}`) - - // Configuração do FluxStack - const config = { - // Valores fixados (build-time) - performance máxima - app: hybridConfig.app, - build: hybridConfig.build, - - // Valores dinâmicos (runtime) - flexibilidade máxima - server: { - port: server.port, // 🔄 Pode mudar sem rebuild - host: server.host, // 🔄 Pode mudar sem rebuild - apiPrefix: server.apiPrefix, - cors: { - origins: env.array('CORS_ORIGINS', ['*']), - enabled: hybridConfig.app.enableCors // ⚡ Fixado no build - } - }, - - logging: { - level: environment.logLevel, // 🔄 Pode mudar sem rebuild - debug: environment.debug - } - } - - return config -} - -// ======================================== -// OTIMIZAÇÃO POR AMBIENTE -// ======================================== - -export function createOptimizedConfig() { - const nodeEnv = env.get('NODE_ENV', 'development') - - switch (nodeEnv) { - case 'development': - return { - // Development: tudo dinâmico para flexibilidade - port: env.num('PORT', 3000), // 🔄 - debug: env.bool('DEBUG', true), // 🔄 - logLevel: env.get('LOG_LEVEL', 'debug'), // 🔄 - hotReload: env.bool('HOT_RELOAD', true) // 🔄 - } - - case 'production': - return { - // Production: mix de fixado e dinâmico - appName: APP_NAME, // ⚡ Fixado (performance) - version: APP_VERSION, // ⚡ Fixado (performance) - port: env.num('PORT', 3000), // 🔄 Dinâmico (deploy) - dbUrl: env.get('DATABASE_URL'), // 🔄 Dinâmico (deploy) - logLevel: env.get('LOG_LEVEL', 'warn') // 🔄 Dinâmico (ops) - } - - default: - return createHybridServer() - } -} - -// ======================================== -// PERFORMANCE COMPARISON -// ======================================== - -export const performanceComparison = { - // ⚡ ULTRA RÁPIDO - Fixado no build - fixedConfig: { - port: 3000, // Literal number - dbUrl: "postgres://...", // Literal string - debug: false // Literal boolean - }, - - // 🔄 LIGEIRAMENTE MAIS LENTO - Dinâmico - dynamicConfig: { - port: env.num('PORT', 3000), // Function call - dbUrl: env.get('DATABASE_URL'), // Function call - debug: env.bool('DEBUG', false) // Function call - } -} - -// ======================================== -// MIGRAÇÃO GRADUAL -// ======================================== - -export const migrationStrategy = { - // Passo 1: Identifique configurações críticas - critical: { - // Use dinâmico para configs que DEVEM mudar - port: env.num('PORT', 3000), - dbUrl: env.get('DATABASE_URL'), - secrets: env.get('JWT_SECRET') - }, - - // Passo 2: Mantenha fixado o que não precisa mudar - static: { - appName: process.env.APP_NAME || 'MyApp', - version: process.env.APP_VERSION || '1.0.0', - features: process.env.FEATURES?.split(',') || [] - }, - - // Passo 3: Migre gradualmente conforme necessário - gradually: { - // Comece com fixado... - logLevel: process.env.LOG_LEVEL || 'info', - - // ...depois mude para dinâmico quando precisar - // logLevel: env.get('LOG_LEVEL', 'info') - } -} - -export default { - hybridConfig, - createHybridServer, - createOptimizedConfig, - performanceComparison, - migrationStrategy -} \ No newline at end of file diff --git a/examples/simplified-env-usage.ts b/examples/simplified-env-usage.ts deleted file mode 100644 index dae25024..00000000 --- a/examples/simplified-env-usage.ts +++ /dev/null @@ -1,251 +0,0 @@ -/** - * Exemplos da API simplificada de Environment Variables - * Mais elegante, intuitiva e com menos código - */ - -import { env, createNamespace, validate, helpers } from '../core/utils/env-runtime-v2' - -// ======================================== -// 1. CASTING AUTOMÁTICO INTELIGENTE -// ======================================== - -// ✅ NOVO - API super simples com casting automático -const config = { - port: env.get('PORT', 3000), // -> number (baseado no default) - debug: env.get('DEBUG', false), // -> boolean (baseado no default) - origins: env.get('CORS_ORIGINS', ['*']), // -> string[] (baseado no default) - host: env.get('HOST', 'localhost'), // -> string (baseado no default) - dbUrl: env.get('DATABASE_URL'), // -> string | undefined - retries: env.get('MAX_RETRIES', 3), // -> number - features: env.get('FEATURES', ['api']) // -> string[] -} - -// ❌ ANTES - API verbosa com métodos específicos -const oldConfig = { - port: env.num('PORT', 3000), - debug: env.bool('DEBUG', false), - origins: env.array('CORS_ORIGINS', ['*']), - host: env.get('HOST', 'localhost'), - dbUrl: env.get('DATABASE_URL'), - retries: env.num('MAX_RETRIES', 3), - features: env.array('FEATURES', ['api']) -} - -// ======================================== -// 2. ACESSO DIRETO COMO PROPRIEDADES -// ======================================== - -console.log(`🚀 Starting on ${env.HOST}:${env.PORT}`) // Direto! -console.log(`📊 Environment: ${env.NODE_ENV}`) // Direto! -console.log(`🐛 Debug mode: ${env.DEBUG}`) // Direto! -console.log(`📋 Swagger: ${env.ENABLE_SWAGGER}`) // Direto! -console.log(`💾 Database: ${env.DATABASE_URL || 'not configured'}`) // Direto! - -// Todos com tipos corretos automaticamente! - -// ======================================== -// 3. CONFIGURAÇÃO DE SERVIDOR SIMPLIFICADA -// ======================================== - -export function createSimpleServer() { - return { - // Casting automático baseado no tipo do default - server: { - port: env.get('PORT', 3000), // number - host: env.get('HOST', 'localhost'), // string - timeout: env.get('TIMEOUT', 30000), // number - keepAlive: env.get('KEEP_ALIVE', true) // boolean - }, - - // Ou acesso direto - database: { - url: env.DATABASE_URL, // string - ssl: env.DB_SSL, // boolean - port: env.DB_PORT, // number - maxConnections: env.get('DB_MAX_CONNECTIONS', 10) // number - }, - - cors: { - origins: env.CORS_ORIGINS, // string[] - credentials: env.get('CORS_CREDENTIALS', false), // boolean - maxAge: env.get('CORS_MAX_AGE', 86400) // number - } - } -} - -// ======================================== -// 4. NAMESPACES PARA ORGANIZAÇÃO -// ======================================== - -// Criar namespaces especializados -const db = createNamespace('DATABASE_') -const redis = createNamespace('REDIS_') -const smtp = createNamespace('SMTP_') - -const databaseConfig = { - url: db.get('URL'), // DATABASE_URL - host: db.get('HOST', 'localhost'), // DATABASE_HOST - port: db.get('PORT', 5432), // DATABASE_PORT (number) - ssl: db.get('SSL', false), // DATABASE_SSL (boolean) - poolSize: db.get('POOL_SIZE', 10), // DATABASE_POOL_SIZE (number) - timeout: db.get('TIMEOUT', 30000) // DATABASE_TIMEOUT (number) -} - -const redisConfig = { - url: redis.get('URL'), // REDIS_URL - host: redis.get('HOST', 'localhost'), // REDIS_HOST - port: redis.get('PORT', 6379), // REDIS_PORT (number) - password: redis.get('PASSWORD') // REDIS_PASSWORD -} - -// ======================================== -// 5. CONFIGURAÇÃO CONDICIONAL ELEGANTE -// ======================================== - -export function createConditionalConfig() { - const config: any = { - app: { - name: env.FLUXSTACK_APP_NAME, // 'FluxStack' - version: env.FLUXSTACK_APP_VERSION // '1.0.0' - }, - - server: { - port: env.PORT, // 3000 - host: env.HOST // 'localhost' - } - } - - // Adicionar database se configurado - if (env.has('DATABASE_URL')) { - config.database = { - url: env.DATABASE_URL, - ssl: env.get('DB_SSL', env.NODE_ENV === 'production') // smart default - } - } - - // Features opcionais - if (env.ENABLE_MONITORING) { - config.monitoring = { - metrics: env.ENABLE_METRICS, - interval: env.get('METRICS_INTERVAL', 30000) - } - } - - return config -} - -// ======================================== -// 6. VALIDAÇÃO SIMPLIFICADA -// ======================================== - -export function validateEnvironment() { - // Vars obrigatórias - validate.require(['NODE_ENV']) - - // Produção precisa de mais vars - if (helpers.isProduction()) { - validate.require(['DATABASE_URL', 'JWT_SECRET']) - } - - // Validar valores específicos - validate.oneOf('NODE_ENV', ['development', 'production', 'test']) - validate.oneOf('LOG_LEVEL', ['debug', 'info', 'warn', 'error']) -} - -// ======================================== -// 7. HELPERS ÚTEIS -// ======================================== - -export function printConfiguration() { - console.log('🔧 Configuration loaded:') - console.log(` Environment: ${env.NODE_ENV}`) - console.log(` Server: ${helpers.getServerUrl()}`) - console.log(` Client: ${helpers.getClientUrl()}`) - console.log(` Database: ${helpers.getDatabaseUrl() || 'not configured'}`) - console.log(` Debug: ${env.DEBUG ? 'enabled' : 'disabled'}`) - console.log(` Swagger: ${env.ENABLE_SWAGGER ? 'enabled' : 'disabled'}`) -} - -// ======================================== -// 8. FLUXSTACK INTEGRATION SIMPLIFICADA -// ======================================== - -import { FluxStackFramework } from '../core/framework/server' - -export function createSimpleFluxStack() { - validateEnvironment() - - const app = new FluxStackFramework({ - app: { - name: env.FLUXSTACK_APP_NAME, // Direto! - version: env.FLUXSTACK_APP_VERSION // Direto! - }, - - server: { - port: env.PORT, // Direto! (number) - host: env.HOST, // Direto! (string) - apiPrefix: env.API_PREFIX, // Direto! (string) - cors: { - origins: env.CORS_ORIGINS, // Direto! (string[]) - credentials: env.get('CORS_CREDENTIALS', false) // boolean - } - }, - - client: { - port: env.VITE_PORT, // Direto! (number) - proxy: { - target: helpers.getServerUrl() // Helper! - } - } - }) - - // Plugins condicionais - if (env.ENABLE_SWAGGER) { - console.log('📋 Swagger enabled') - // app.use(swaggerPlugin) - } - - if (env.ENABLE_MONITORING) { - console.log('📊 Monitoring enabled') - // app.use(monitoringPlugin) - } - - return app -} - -// ======================================== -// 9. COMPARAÇÃO ANTES vs DEPOIS -// ======================================== - -// ❌ ANTES - Verboso -const beforeConfig = { - port: env.num('PORT', 3000), - debug: env.bool('DEBUG', false), - origins: env.array('CORS_ORIGINS', ['*']), - retries: env.num('MAX_RETRIES', 3), - timeout: env.num('TIMEOUT', 30000) -} - -// ✅ DEPOIS - Limpo e elegante -const afterConfig = { - port: env.get('PORT', 3000), // casting automático - debug: env.get('DEBUG', false), // casting automático - origins: env.get('CORS_ORIGINS', ['*']), // casting automático - retries: env.get('MAX_RETRIES', 3), // casting automático - timeout: env.get('TIMEOUT', 30000) // casting automático -} - -// Ou ainda mais simples com propriedades diretas: -const simpleConfig = { - port: env.PORT, // Direto da propriedade - debug: env.DEBUG, // Direto da propriedade - origins: env.CORS_ORIGINS // Direto da propriedade -} - -export default { - createSimpleServer, - createConditionalConfig, - validateEnvironment, - printConfiguration, - createSimpleFluxStack -} \ No newline at end of file diff --git a/flux-cli.ts b/flux-cli.ts new file mode 100644 index 00000000..128c5827 --- /dev/null +++ b/flux-cli.ts @@ -0,0 +1,214 @@ +#!/usr/bin/env bun + +/** + * FluxStack CLI - Comando nativo `flux` + * Permite criar projetos sem dependências externas ou configurações manuais + */ + +import { promises as fs } from 'fs'; +import path from 'path'; +import { spawn } from 'child_process'; + +interface CreateProjectOptions { + name: string; + template?: 'basic' | 'minimal' | 'full'; +} + +async function createProject(options: CreateProjectOptions) { + const { name, template = 'basic' } = options; + const projectPath = path.resolve(name); + + console.log(`🚀 Creating FluxStack project: ${name}`); + console.log(`📋 Template: ${template}`); + console.log(`📁 Location: ${projectPath}`); + console.log(); + + // Check if directory exists + try { + await fs.access(projectPath); + console.error(`❌ Directory "${name}" already exists`); + process.exit(1); + } catch (error: any) { + if (error.code !== 'ENOENT') { + throw error; + } + } + + // Create project directory + await fs.mkdir(projectPath, { recursive: true }); + + // Copy template + const templatePath = path.resolve(__dirname, 'templates', template); + await copyDirectory(templatePath, projectPath); + + // Process placeholders + await processTemplateFiles(projectPath, { + PROJECT_NAME: name, + PROJECT_DESCRIPTION: `A FluxStack application named ${name}` + }); + + console.log('✅ Project structure created!'); + console.log('📦 Installing dependencies...'); + + // Install dependencies + await installDependencies(projectPath); + + console.log(); + console.log('🎉 Project created successfully!'); + console.log(); + console.log('Next steps:'); + console.log(` cd ${name}`); + console.log(' bun run dev'); + console.log(); + console.log('Happy coding! 🚀'); +} + +async function copyDirectory(src: string, dest: string, exclude: string[] = ['node_modules', '.git', 'dist']) { + await fs.mkdir(dest, { recursive: true }); + + try { + const entries = await fs.readdir(src, { withFileTypes: true }); + + for (const entry of entries) { + if (exclude.includes(entry.name)) continue; + + const srcPath = path.join(src, entry.name); + const destPath = path.join(dest, entry.name); + + if (entry.isDirectory()) { + await copyDirectory(srcPath, destPath, exclude); + } else { + const content = await fs.readFile(srcPath, 'utf-8'); + await fs.writeFile(destPath, content, 'utf-8'); + } + } + } catch (error) { + console.error(`❌ Template not found at: ${src}`); + console.error('Make sure you have the templates directory in your FluxStack installation.'); + process.exit(1); + } +} + +async function processTemplateFiles( + projectPath: string, + replacements: Record +) { + const files = await getAllFiles(projectPath); + + for (const file of files) { + // Skip binary files + if (isBinaryFile(file)) continue; + + let content = await fs.readFile(file, 'utf-8'); + + // Replace placeholders + for (const [key, value] of Object.entries(replacements)) { + const regex = new RegExp(`{{${key}}}`, 'g'); + content = content.replace(regex, value); + } + + await fs.writeFile(file, content, 'utf-8'); + } +} + +async function getAllFiles(dirPath: string): Promise { + const files: string[] = []; + const items = await fs.readdir(dirPath, { withFileTypes: true }); + + for (const item of items) { + const fullPath = path.join(dirPath, item.name); + + if (item.isDirectory()) { + files.push(...await getAllFiles(fullPath)); + } else { + files.push(fullPath); + } + } + + return files; +} + +function isBinaryFile(filePath: string): boolean { + const binaryExtensions = ['.png', '.jpg', '.jpeg', '.gif', '.ico', '.svg', '.woff', '.woff2', '.ttf', '.eot']; + const ext = path.extname(filePath).toLowerCase(); + return binaryExtensions.includes(ext); +} + +async function installDependencies(projectPath: string): Promise { + return new Promise((resolve, reject) => { + const install = spawn('bun', ['install'], { + cwd: projectPath, + stdio: 'inherit' + }); + + install.on('close', (code) => { + if (code === 0) { + resolve(); + } else { + reject(new Error(`Dependencies installation failed with code ${code}`)); + } + }); + + install.on('error', reject); + }); +} + +function showHelp() { + console.log(` +🚀 FluxStack CLI + +Usage: + flux create Create a new FluxStack project + flux create --template Specify template (basic, minimal, full) + flux --help Show this help + +Examples: + flux create my-app Create basic project + flux create my-blog --template basic Create with basic template + flux create my-api --template minimal Create minimal project + +Templates: + basic Full-featured app with frontend and backend (default) + minimal Just the backend API + full Everything + advanced features + +Get started in seconds! 🔥 +`); +} + +// Parse command line arguments +const args = process.argv.slice(2); +const command = args[0]; + +if (!command || command === '--help' || command === 'help') { + showHelp(); + process.exit(0); +} + +if (command === 'create') { + const projectName = args[1]; + + if (!projectName) { + console.error('❌ Please provide a project name'); + console.error('Usage: flux create '); + process.exit(1); + } + + // Validate project name + if (!/^[a-zA-Z0-9-_]+$/.test(projectName)) { + console.error('❌ Project name can only contain letters, numbers, hyphens, and underscores'); + process.exit(1); + } + + const templateIndex = args.indexOf('--template'); + const template = templateIndex !== -1 ? args[templateIndex + 1] as 'basic' | 'minimal' | 'full' : 'basic'; + + createProject({ name: projectName, template }).catch(error => { + console.error('❌ Error creating project:', error.message); + process.exit(1); + }); +} else { + console.error(`❌ Unknown command: ${command}`); + console.error('Run "flux --help" for available commands'); + process.exit(1); +} \ No newline at end of file diff --git a/package-template.json b/package-template.json new file mode 100644 index 00000000..1e032f43 --- /dev/null +++ b/package-template.json @@ -0,0 +1,68 @@ +{ + "name": "PROJECT_NAME", + "version": "1.0.0", + "description": "PROJECT_NAME - FluxStack application", + "keywords": ["fluxstack", "bun", "typescript", "full-stack", "elysia", "react", "vite"], + "author": "Your Name", + "license": "MIT", + "type": "module", + "scripts": { + "dev": "bun core/cli/index.ts dev", + "dev:clean": "bun run-clean.ts", + "dev:backend": "bun core/cli/index.ts dev:backend", + "dev:frontend": "bun core/cli/index.ts dev:frontend", + "build": "bun core/cli/index.ts build", + "build:backend": "bun core/cli/index.ts build:backend", + "build:frontend": "bun core/cli/index.ts build:frontend", + "start": "NODE_ENV=production bun app/server/index.ts", + "start:backend": "NODE_ENV=production bun app/server/backend-only.ts", + "start:frontend": "NODE_ENV=production bun app/client/frontend-only.ts", + "typecheck": "bunx tsc --noEmit", + "test": "vitest", + "test:ui": "vitest --ui", + "test:coverage": "vitest --coverage" + }, + "devDependencies": { + "@eslint/js": "^9.30.1", + "@tailwindcss/vite": "^4.1.13", + "@testing-library/jest-dom": "^6.6.4", + "@testing-library/react": "^16.3.0", + "@testing-library/user-event": "^14.6.1", + "@types/bun": "latest", + "@types/node": "^24.5.2", + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitest/coverage-v8": "^3.2.4", + "@vitest/ui": "^3.2.4", + "concurrently": "^9.2.0", + "eslint": "^9.30.1", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.3.0", + "jsdom": "^26.1.0", + "tailwindcss": "^4.1.13", + "typescript": "^5.8.3", + "typescript-eslint": "^8.35.1", + "vitest": "^3.2.4" + }, + "dependencies": { + "@elysiajs/eden": "^1.3.2", + "@elysiajs/swagger": "^1.3.1", + "@types/http-proxy-middleware": "^1.0.0", + "@vitejs/plugin-react": "^4.6.0", + "chokidar": "^4.0.3", + "elysia": "^1.4.6", + "http-proxy-middleware": "^3.0.5", + "lightningcss": "^1.30.1", + "lucide-react": "^0.544.0", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "vite": "^7.0.4" + }, + "engines": { + "bun": ">=1.2.0", + "node": ">=20.0.0" + }, + "preferredPackageManager": "bun", + "trustedDependencies": ["esbuild"] +} \ No newline at end of file diff --git a/package.json b/package.json index 3f8b6ad7..aee14d63 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "fluxstack", - "version": "1.0.0", + "name": "create-fluxstack", + "version": "1.0.5", "description": "⚡ Modern full-stack TypeScript framework with Elysia + React + Bun", "keywords": ["framework", "full-stack", "typescript", "elysia", "react", "bun", "vite"], "author": "FluxStack Team", @@ -13,8 +13,7 @@ "module": "app/server/index.ts", "type": "module", "bin": { - "fluxstack": "./core/cli/index.ts", - "flux": "./core/cli/index.ts" + "create-fluxstack": "./create-fluxstack.ts" }, "scripts": { "dev": "bun run core/cli/index.ts dev", @@ -71,11 +70,14 @@ "@elysiajs/swagger": "^1.3.1", "@types/http-proxy-middleware": "^1.0.0", "@vitejs/plugin-react": "^4.6.0", + "chalk": "^5.3.0", "chokidar": "^4.0.3", + "commander": "^12.1.0", "elysia": "^1.4.6", "http-proxy-middleware": "^3.0.5", "lightningcss": "^1.30.1", "lucide-react": "^0.544.0", + "ora": "^8.1.0", "react": "^19.1.0", "react-dom": "^19.1.0", "vite": "^7.0.4" diff --git a/publish.sh b/publish.sh new file mode 100644 index 00000000..0cbdf460 --- /dev/null +++ b/publish.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +# 🚀 FluxStack CLI Publication Script +# Este script automatiza a publicação do create-fluxstack no NPM + +set -e + +echo "⚡ FluxStack CLI Publication Setup" +echo "================================" + +# Check if we're in the right directory +if [[ ! -f "create-fluxstack.ts" ]]; then + echo "❌ create-fluxstack.ts not found. Run this script from FluxStack root directory." + exit 1 +fi + +echo "📋 Pre-publication checklist:" +echo "" + +# 1. Test CLI +echo "🧪 Testing CLI..." +if ./create-fluxstack.ts test-publish-app --no-install --no-git; then + echo "✅ CLI test passed" + rm -rf test-publish-app +else + echo "❌ CLI test failed" + exit 1 +fi + +# 2. Setup package.json for publication +echo "📦 Setting up package.json..." +cp package-cli.json package.json.publish +echo "✅ Package configuration ready" + +# 3. Setup README for publication +echo "📖 Setting up README..." +cp README-CLI.md README.publish.md +echo "✅ README ready" + +echo "" +echo "🎯 Ready to publish! Next steps:" +echo "" +echo "1. Review files:" +echo " - package.json.publish" +echo " - README.publish.md" +echo " - create-fluxstack.ts" +echo "" +echo "2. Publish to NPM:" +echo " cp package.json.publish package.json" +echo " cp README.publish.md README.md" +echo " npm login" +echo " npm publish" +echo "" +echo "3. Or create GitHub release:" +echo " git add ." +echo " git commit -m 'feat: create-fluxstack CLI v1.0.0'" +echo " git tag v1.0.0" +echo " git push origin main --tags" +echo "" +echo "4. Test installation:" +echo " bunx create-fluxstack my-test-app" +echo "" +echo "🚀 Ready to make FluxStack available to the world!" \ No newline at end of file diff --git a/workspace.json b/workspace.json new file mode 100644 index 00000000..bbe413e6 --- /dev/null +++ b/workspace.json @@ -0,0 +1,6 @@ +{ + "name": "fluxstack-workspace", + "workspaces": [ + "./packages/*" + ] +} \ No newline at end of file From 8f7a73b3e75753269acfad3319612e3358428b36 Mon Sep 17 00:00:00 2001 From: FluxStack Team Date: Thu, 25 Sep 2025 11:35:55 -0300 Subject: [PATCH 2/2] feat: complete create-fluxstack CLI with production-ready features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Major improvements: - Fix message formatting (remove double-escaped newlines) - Add comprehensive README with full documentation - Update to Bun-only requirements (>=1.2.0, remove Node.js support) - Include .gitignore in generated projects - Add ai-context/ and CLAUDE.md to CLI output - Create .env from .env.example template with development mode - Update package-template.json with correct dependencies - Publish create-fluxstack@1.0.10 to NPM CLI now provides: ✅ Zero-configuration project creation ✅ Complete FluxStack framework (159 files, 1.1 MB) ✅ Professional user experience with clean output ✅ Git repository initialization with proper .gitignore ✅ AI assistant documentation included ✅ Type-safe API development with Eden Treaty ✅ Hot reload coordination between backend and frontend 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- README.md | 297 ++++++++++++++++++++++++++++-------------- create-fluxstack.ts | 11 +- package-template.json | 3 +- package.json | 12 +- 4 files changed, 214 insertions(+), 109 deletions(-) diff --git a/README.md b/README.md index 5b862419..2a179648 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # ⚡ create-fluxstack -> Create FluxStack apps with zero configuration - powered by Bun +> Create modern full-stack TypeScript applications with zero configuration -[![npm version](https://badge.fury.io/js/create-fluxstack.svg)](https://badge.fury.io/js/create-fluxstack) +[![npm version](https://badge.fury.io/js/create-fluxstack.svg)](https://www.npmjs.com/package/create-fluxstack) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) ## 🚀 Quick Start @@ -11,18 +11,15 @@ # Create a new FluxStack app bunx create-fluxstack my-awesome-app -# Or with npx -npx create-fluxstack my-awesome-app - # Navigate and start developing cd my-awesome-app bun run dev ``` **That's it!** Your full-stack TypeScript app is ready at: -- **Backend**: http://localhost:3000 -- **Frontend**: http://localhost:5173 -- **API Docs**: http://localhost:3000/swagger +- 🚀 **Backend**: http://localhost:3000 +- ⚛️ **Frontend**: http://localhost:5173 +- 📋 **API Docs**: http://localhost:3000/swagger ## ✨ What You Get @@ -34,24 +31,35 @@ bun run dev - **📦 Vite 7** - Lightning-fast dev server - **🔒 TypeScript 5** - Full type safety end-to-end -### 🛠️ Zero Configuration -- **✅ Hot Reload** - Backend + Frontend coordinated -- **✅ Type Safety** - Eden Treaty for API communication -- **✅ Auto Documentation** - Swagger UI generated -- **✅ Git Ready** - Initialized with first commit -- **✅ Production Ready** - Build scripts included +### 🛠️ Zero Configuration Features +- **✅ Type Safety** - Eden Treaty for API communication with automatic type inference +- **✅ Hot Reload** - Backend + Frontend coordinated development +- **✅ Auto Documentation** - Swagger UI generated from your API +- **✅ Git Ready** - Repository initialized with proper .gitignore +- **✅ Production Ready** - Optimized build scripts included +- **✅ AI Context** - Complete documentation for AI assistants ## 📁 Project Structure ``` my-awesome-app/ -├── core/ # FluxStack framework (don't modify) -├── app/ # Your application code -│ ├── server/ # Backend API routes -│ ├── client/ # Frontend React app -│ └── shared/ # Shared types and utilities -├── package.json # Dependencies and scripts -└── README.md # Project documentation +├── core/ # FluxStack framework (don't modify) +│ ├── server/ # Framework server components +│ ├── config/ # Configuration system +│ ├── plugins/ # Built-in plugins (logger, swagger, etc) +│ └── cli/ # Development CLI tools +├── app/ # Your application code +│ ├── server/ # Backend API routes +│ │ ├── controllers/ # Business logic +│ │ └── routes/ # API endpoints +│ ├── client/ # Frontend React app +│ │ ├── src/ # React components +│ │ └── public/ # Static assets +│ └── shared/ # Shared types and utilities +├── ai-context/ # AI assistant documentation +├── package.json # Dependencies and scripts +├── CLAUDE.md # AI instructions +└── README.md # Project documentation ``` ## 🎯 Available Scripts @@ -59,8 +67,9 @@ my-awesome-app/ ```bash # Development bun run dev # Start full-stack development -bun run dev:frontend # Frontend only -bun run dev:backend # Backend only +bun run dev:clean # Clean output (no Elysia HEAD logs) +bun run dev:frontend # Frontend only (port 5173) +bun run dev:backend # Backend only (port 3001) # Production bun run build # Build for production @@ -68,60 +77,90 @@ bun run start # Start production server # Utilities bun run typecheck # Check TypeScript +bun run test # Run test suite ``` -## 🔧 Requirements +## 🔧 Type-Safe API Development -- **Bun** >= 1.0.0 (recommended) -- **Node.js** >= 18.0.0 (fallback) +FluxStack provides automatic type inference between your backend and frontend using Eden Treaty: -### Install Bun +### Backend API (Elysia.js) +```typescript +// app/server/routes/users.ts +import { Elysia, t } from 'elysia' -```bash -# Install Bun (if not already installed) -curl -fsSL https://bun.sh/install | bash +export const userRoutes = new Elysia({ prefix: '/users' }) + .get('/', () => ({ users: getAllUsers() })) + .post('/', ({ body }) => createUser(body), { + body: t.Object({ + name: t.String(), + email: t.String({ format: 'email' }) + }), + response: t.Object({ + success: t.Boolean(), + user: t.Optional(t.Object({ + id: t.Number(), + name: t.String(), + email: t.String(), + createdAt: t.Date() + })) + }) + }) ``` -## 🎨 Customization - -### Environment Variables +### Frontend with Type Safety +```typescript +// app/client/src/components/Users.tsx +import { api } from '../lib/eden-api' + +export function UsersList() { + const [users, setUsers] = useState([]) + + const createUser = async (userData: CreateUserData) => { + // ✨ Fully typed - no manual type definitions needed! + const { data, error } = await api.users.post(userData) + + if (!error) { + setUsers(prev => [...prev, data.user]) // ✅ TypeScript knows the shape + } + } + + return ( +
+ {users.map(user => ( + + ))} +
+ ) +} +``` -The generated app uses these environment variables (in `.env`): +## 🌍 Environment & Configuration +### Environment Variables ```bash +# .env (auto-generated from .env.example) NODE_ENV=development PORT=3000 HOST=localhost VITE_PORT=5173 VITE_API_URL=http://localhost:3000 -``` - -### Adding Routes - -Backend routes in `app/server/routes/`: - -```typescript -// app/server/routes/users.ts -import { Elysia } from 'elysia' -export const userRoutes = new Elysia({ prefix: '/users' }) - .get('/', () => ({ users: [] })) - .post('/', ({ body }) => ({ user: body })) +# Add your own variables +DATABASE_URL=postgresql://localhost:5432/myapp +JWT_SECRET=your-secret-key ``` -Frontend API calls with type safety: - +### Frontend Environment ```typescript -// app/client/src/components/Users.tsx -import { api } from '../lib/api' - -const users = await api.users.get() // ✅ Fully typed! +// Only VITE_* variables are exposed to frontend +const apiUrl = import.meta.env.VITE_API_URL +const appName = import.meta.env.VITE_APP_NAME ``` ## 🚀 Deployment -### Option 1: Single Server (Recommended) - +### Single Server (Recommended) ```bash # Build everything bun run build @@ -130,85 +169,147 @@ bun run build bun run start ``` -### Option 2: Separate Deploy - +### Separate Deploy ```bash # Backend bun run build:backend bun dist/index.js -# Frontend +# Frontend bun run build:frontend # Deploy dist/ folder to CDN ``` -## 🤝 Examples +### Docker +```bash +# Use included Dockerfile +docker build -t my-app . +docker run -p 3000:3000 my-app +``` + +## 🔧 Requirements + +- **Bun** >= 1.2.0 (required) + +### Install Bun +```bash +# macOS/Linux +curl -fsSL https://bun.sh/install | bash + +# Windows +powershell -c "irm bun.sh/install.ps1|iex" +``` + +> **Note**: FluxStack is built specifically for Bun runtime. Node.js is not supported. -### Basic CRUD API +## 🎨 Customization +### Adding API Routes ```typescript -// app/server/routes/posts.ts +// app/server/routes/posts.ts +import { Elysia, t } from 'elysia' + export const postRoutes = new Elysia({ prefix: '/posts' }) .get('/', () => ({ posts: [] })) - .post('/', ({ body }) => ({ id: 1, ...body })) - .get('/:id', ({ params }) => ({ id: params.id })) -``` + .post('/', ({ body }) => ({ post: body }), { + body: t.Object({ + title: t.String(), + content: t.String() + }) + }) -### Frontend Integration +// app/server/index.ts +import { postRoutes } from './routes/posts' +app.use(postRoutes) +``` + +### Custom Plugins ```typescript -// app/client/src/hooks/usePosts.ts -import { api } from '../lib/api' +// app/server/plugins/auth.ts +import { Elysia } from 'elysia' -export function usePosts() { - return useQuery({ - queryKey: ['posts'], - queryFn: () => api.posts.get() +export const authPlugin = new Elysia({ name: 'auth' }) + .derive(({ headers }) => ({ + user: getUserFromToken(headers.authorization) + })) + .guard({ + beforeHandle({ user, set }) { + if (!user) { + set.status = 401 + return { error: 'Unauthorized' } + } + } }) -} ``` -## 🛟 Troubleshooting +## 📚 Documentation & AI Support -### Port Already in Use +FluxStack includes comprehensive documentation for both developers and AI assistants: -```bash -# Kill processes on ports -pkill -f "3000" -pkill -f "5173" -``` +- **📖 Full Documentation**: Check the `ai-context/` folder +- **🤖 AI Instructions**: See `CLAUDE.md` for AI assistant guidance +- **⚡ Quick Start**: `ai-context/00-QUICK-START.md` +- **🎯 Examples**: Complete CRUD examples included -### Type Errors +## 🛟 Support & Community -```bash -# Regenerate types -bun run typecheck -``` +- **🐛 Issues**: [Report bugs](https://github.com/MarcosBrendonDePaula/FluxStack/issues) +- **📖 Documentation**: [Full docs](https://github.com/MarcosBrendonDePaula/FluxStack) +- **💬 Discussions**: [GitHub Discussions](https://github.com/MarcosBrendonDePaula/FluxStack/discussions) -### Environment Issues +## 🔄 Upgrading ```bash -# Force development mode -NODE_ENV=development bun run dev +# Get the latest version +bunx create-fluxstack@latest my-new-app + +# Check current version +npm list -g create-fluxstack ``` -## 📖 Learn More +## 🌟 Why FluxStack? -- [FluxStack Documentation](https://fluxstack.dev) -- [Bun Runtime](https://bun.sh) -- [Elysia.js](https://elysiajs.com) -- [React 19](https://react.dev) +### ✅ **Developer Experience** +- **Zero Config**: Just create and start coding +- **Type Safety**: End-to-end without manual work +- **Hot Reload**: Backend and frontend in sync +- **Auto Docs**: Swagger generated from your code -## 🐛 Issues & Contributing +### ✅ **Performance** +- **Bun Runtime**: 3x faster than Node.js +- **Elysia**: One of the fastest TypeScript frameworks +- **Vite**: Instant HMR and optimized builds +- **React 19**: Latest performance improvements -Found a bug? Have a suggestion? -- [GitHub Issues](https://github.com/fluxstack/create-fluxstack/issues) -- [GitHub Discussions](https://github.com/fluxstack/create-fluxstack/discussions) +### ✅ **Production Ready** +- **Docker**: Optimized containers included +- **Environment**: Robust configuration system +- **Error Handling**: Consistent error responses +- **Monitoring**: Built-in observability features -## 📄 License +### ✅ **Modern Stack** +- **TypeScript 5**: Latest language features +- **React 19**: Concurrent features, Server Components ready +- **Tailwind v4**: Latest CSS framework +- **Eden Treaty**: Revolutionary type-safe API client -MIT © FluxStack Team +## 🎊 Get Started Now! + +```bash +bunx create-fluxstack my-dream-app +cd my-dream-app +bun run dev +``` + +**Welcome to the future of full-stack development!** ⚡🚀 --- -**Happy coding with the divine Bun runtime! ⚡🔥** \ No newline at end of file +
+ +**Built with ❤️ by the FluxStack Team** + +[⭐ Star on GitHub](https://github.com/MarcosBrendonDePaula/FluxStack) • [📦 NPM Package](https://www.npmjs.com/package/create-fluxstack) + +
\ No newline at end of file diff --git a/create-fluxstack.ts b/create-fluxstack.ts index 00c4638c..a433a50e 100644 --- a/create-fluxstack.ts +++ b/create-fluxstack.ts @@ -43,7 +43,7 @@ program process.exit(1) } - console.log(chalk.cyan(`\\n🚀 Creating FluxStack project: ${chalk.bold(projectName)}`)) + console.log(chalk.cyan(`\n🚀 Creating FluxStack project: ${chalk.bold(projectName)}`)) console.log(chalk.gray(`📁 Location: ${projectPath}`)) // Create project directory @@ -62,6 +62,7 @@ program 'tsconfig.json', 'vite.config.ts', '.env.example', // ✅ Use .env.example as template + '.gitignore', // ✅ Git ignore file for proper repository setup 'CLAUDE.md', // ✅ Project instructions for AI assistants 'README.md' ] @@ -229,15 +230,15 @@ Built with ❤️ using FluxStack } // Success message - console.log(chalk.green('\\n🎉 Project created successfully!')) - console.log(chalk.cyan('\\nNext steps:')) + console.log(chalk.green('\n🎉 Project created successfully!')) + console.log(chalk.cyan('\nNext steps:')) console.log(chalk.white(` cd ${projectName}`)) if (!options.install) { console.log(chalk.white(` bun install`)) } console.log(chalk.white(` bun run dev`)) - console.log(chalk.magenta('\\nHappy coding with the divine Bun runtime! ⚡🔥')) - console.log(chalk.gray('\\nVisit http://localhost:3000 when ready!')) + console.log(chalk.magenta('\nHappy coding with the divine Bun runtime! ⚡🔥')) + console.log(chalk.gray('\nVisit http://localhost:3000 when ready!')) } catch (error) { spinner.fail('❌ Failed to create project') diff --git a/package-template.json b/package-template.json index 1e032f43..95b81274 100644 --- a/package-template.json +++ b/package-template.json @@ -60,8 +60,7 @@ "vite": "^7.0.4" }, "engines": { - "bun": ">=1.2.0", - "node": ">=20.0.0" + "bun": ">=1.2.0" }, "preferredPackageManager": "bun", "trustedDependencies": ["esbuild"] diff --git a/package.json b/package.json index aee14d63..fb1a5f15 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,14 @@ { "name": "create-fluxstack", - "version": "1.0.5", + "version": "1.0.10", "description": "⚡ Modern full-stack TypeScript framework with Elysia + React + Bun", "keywords": ["framework", "full-stack", "typescript", "elysia", "react", "bun", "vite"], "author": "FluxStack Team", "license": "MIT", - "homepage": "https://github.com/fluxstack/fluxstack", + "homepage": "https://github.com/MarcosBrendonDePaula/FluxStack", "repository": { "type": "git", - "url": "https://github.com/fluxstack/fluxstack.git" + "url": "https://github.com/MarcosBrendonDePaula/FluxStack.git" }, "module": "app/server/index.ts", "type": "module", @@ -81,5 +81,9 @@ "react": "^19.1.0", "react-dom": "^19.1.0", "vite": "^7.0.4" - } + }, + "engines": { + "bun": ">=1.2.0" + }, + "preferredPackageManager": "bun" } \ No newline at end of file