create-fluxstack 1.10.1 → 1.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +1 -2
- package/Dockerfile +8 -8
- package/LLMD/INDEX.md +64 -0
- package/LLMD/MAINTENANCE.md +197 -0
- package/LLMD/MIGRATION.md +156 -0
- package/LLMD/config/.gitkeep +1 -0
- package/LLMD/config/declarative-system.md +268 -0
- package/LLMD/config/environment-vars.md +327 -0
- package/LLMD/config/runtime-reload.md +401 -0
- package/LLMD/core/.gitkeep +1 -0
- package/LLMD/core/build-system.md +599 -0
- package/LLMD/core/framework-lifecycle.md +229 -0
- package/LLMD/core/plugin-system.md +451 -0
- package/LLMD/patterns/.gitkeep +1 -0
- package/LLMD/patterns/anti-patterns.md +297 -0
- package/LLMD/patterns/project-structure.md +264 -0
- package/LLMD/patterns/type-safety.md +440 -0
- package/LLMD/reference/.gitkeep +1 -0
- package/LLMD/reference/cli-commands.md +250 -0
- package/LLMD/reference/plugin-hooks.md +357 -0
- package/LLMD/reference/routing.md +39 -0
- package/LLMD/reference/troubleshooting.md +364 -0
- package/LLMD/resources/.gitkeep +1 -0
- package/LLMD/resources/controllers.md +465 -0
- package/LLMD/resources/live-components.md +703 -0
- package/LLMD/resources/live-rooms.md +482 -0
- package/LLMD/resources/live-upload.md +130 -0
- package/LLMD/resources/plugins-external.md +617 -0
- package/LLMD/resources/routes-eden.md +254 -0
- package/README.md +37 -17
- package/app/client/index.html +0 -1
- package/app/client/src/App.tsx +107 -150
- package/app/client/src/components/AppLayout.tsx +68 -0
- package/app/client/src/components/BackButton.tsx +13 -0
- package/app/client/src/components/DemoPage.tsx +20 -0
- package/app/client/src/components/LiveUploadWidget.tsx +204 -0
- package/app/client/src/lib/eden-api.ts +85 -60
- package/app/client/src/live/ChatDemo.tsx +107 -0
- package/app/client/src/live/CounterDemo.tsx +206 -0
- package/app/client/src/live/FormDemo.tsx +119 -0
- package/app/client/src/live/RoomChatDemo.tsx +161 -0
- package/app/client/src/live/UploadDemo.tsx +21 -0
- package/app/client/src/main.tsx +4 -1
- package/app/client/src/pages/ApiTestPage.tsx +108 -0
- package/app/client/src/pages/HomePage.tsx +76 -0
- package/app/server/app.ts +1 -4
- package/app/server/controllers/users.controller.ts +36 -44
- package/app/server/index.ts +25 -35
- package/app/server/live/LiveChat.ts +77 -0
- package/app/server/live/LiveCounter.ts +67 -0
- package/app/server/live/LiveForm.ts +63 -0
- package/app/server/live/LiveLocalCounter.ts +32 -0
- package/app/server/live/LiveRoomChat.ts +127 -0
- package/app/server/live/LiveUpload.ts +81 -0
- package/app/server/routes/index.ts +3 -1
- package/app/server/routes/room.routes.ts +117 -0
- package/app/server/routes/users.routes.ts +35 -27
- package/app/shared/types/index.ts +14 -2
- package/config/app.config.ts +2 -62
- package/config/client.config.ts +2 -95
- package/config/database.config.ts +2 -99
- package/config/fluxstack.config.ts +25 -45
- package/config/index.ts +57 -38
- package/config/monitoring.config.ts +2 -114
- package/config/plugins.config.ts +2 -80
- package/config/server.config.ts +2 -68
- package/config/services.config.ts +2 -130
- package/config/system/app.config.ts +29 -0
- package/config/system/build.config.ts +49 -0
- package/config/system/client.config.ts +68 -0
- package/config/system/database.config.ts +17 -0
- package/config/system/fluxstack.config.ts +114 -0
- package/config/{logger.config.ts → system/logger.config.ts} +3 -1
- package/config/system/monitoring.config.ts +114 -0
- package/config/system/plugins.config.ts +84 -0
- package/config/{runtime.config.ts → system/runtime.config.ts} +1 -1
- package/config/system/server.config.ts +68 -0
- package/config/system/services.config.ts +46 -0
- package/config/{system.config.ts → system/system.config.ts} +1 -1
- package/core/build/flux-plugins-generator.ts +325 -325
- package/core/build/index.ts +39 -27
- package/core/build/live-components-generator.ts +3 -3
- package/core/build/optimizer.ts +235 -235
- package/core/cli/command-registry.ts +6 -4
- package/core/cli/commands/build.ts +79 -0
- package/core/cli/commands/create.ts +54 -0
- package/core/cli/commands/dev.ts +101 -0
- package/core/cli/commands/help.ts +34 -0
- package/core/cli/commands/index.ts +34 -0
- package/core/cli/commands/make-plugin.ts +90 -0
- package/core/cli/commands/plugin-add.ts +197 -0
- package/core/cli/commands/plugin-deps.ts +2 -2
- package/core/cli/commands/plugin-list.ts +208 -0
- package/core/cli/commands/plugin-remove.ts +170 -0
- package/core/cli/generators/component.ts +769 -769
- package/core/cli/generators/controller.ts +1 -1
- package/core/cli/generators/index.ts +146 -146
- package/core/cli/generators/interactive.ts +227 -227
- package/core/cli/generators/plugin.ts +2 -2
- package/core/cli/generators/prompts.ts +82 -82
- package/core/cli/generators/route.ts +6 -6
- package/core/cli/generators/service.ts +2 -2
- package/core/cli/generators/template-engine.ts +4 -3
- package/core/cli/generators/types.ts +2 -2
- package/core/cli/generators/utils.ts +191 -191
- package/core/cli/index.ts +115 -686
- package/core/cli/plugin-discovery.ts +2 -2
- package/core/client/LiveComponentsProvider.tsx +60 -8
- package/core/client/api/eden.ts +183 -0
- package/core/client/api/index.ts +11 -0
- package/core/client/components/Live.tsx +104 -0
- package/core/client/fluxstack.ts +1 -9
- package/core/client/hooks/AdaptiveChunkSizer.ts +215 -215
- package/core/client/hooks/state-validator.ts +1 -1
- package/core/client/hooks/useAuth.ts +48 -48
- package/core/client/hooks/useChunkedUpload.ts +85 -35
- package/core/client/hooks/useLiveChunkedUpload.ts +87 -0
- package/core/client/hooks/useLiveComponent.ts +800 -0
- package/core/client/hooks/useLiveUpload.ts +71 -0
- package/core/client/hooks/useRoom.ts +409 -0
- package/core/client/hooks/useRoomProxy.ts +382 -0
- package/core/client/index.ts +17 -68
- package/core/client/standalone-entry.ts +8 -0
- package/core/client/standalone.ts +74 -53
- package/core/client/state/createStore.ts +192 -192
- package/core/client/state/index.ts +14 -14
- package/core/config/index.ts +70 -291
- package/core/config/schema.ts +42 -723
- package/core/framework/client.ts +131 -131
- package/core/framework/index.ts +7 -7
- package/core/framework/server.ts +47 -40
- package/core/framework/types.ts +2 -2
- package/core/index.ts +23 -4
- package/core/live/ComponentRegistry.ts +3 -3
- package/core/live/types.ts +77 -0
- package/core/plugins/built-in/index.ts +134 -134
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +242 -1066
- package/core/plugins/built-in/live-components/index.ts +1 -1
- package/core/plugins/built-in/monitoring/index.ts +111 -47
- package/core/plugins/built-in/static/index.ts +1 -1
- package/core/plugins/built-in/swagger/index.ts +68 -265
- package/core/plugins/built-in/vite/index.ts +85 -185
- package/core/plugins/built-in/vite/vite-dev.ts +10 -16
- package/core/plugins/config.ts +9 -7
- package/core/plugins/dependency-manager.ts +31 -1
- package/core/plugins/discovery.ts +19 -7
- package/core/plugins/executor.ts +2 -2
- package/core/plugins/index.ts +203 -203
- package/core/plugins/manager.ts +27 -39
- package/core/plugins/module-resolver.ts +19 -8
- package/core/plugins/registry.ts +255 -19
- package/core/plugins/types.ts +20 -53
- package/core/server/framework.ts +66 -43
- package/core/server/index.ts +15 -15
- package/core/server/live/ComponentRegistry.ts +78 -71
- package/core/server/live/FileUploadManager.ts +23 -10
- package/core/server/live/LiveComponentPerformanceMonitor.ts +1 -1
- package/core/server/live/LiveRoomManager.ts +261 -0
- package/core/server/live/RoomEventBus.ts +234 -0
- package/core/server/live/RoomStateManager.ts +172 -0
- package/core/server/live/StateSignature.ts +643 -643
- package/core/server/live/WebSocketConnectionManager.ts +30 -19
- package/core/server/live/auto-generated-components.ts +21 -9
- package/core/server/live/index.ts +14 -0
- package/core/server/live/websocket-plugin.ts +214 -67
- package/core/server/middleware/elysia-helpers.ts +7 -2
- package/core/server/middleware/errorHandling.ts +1 -1
- package/core/server/middleware/index.ts +31 -31
- package/core/server/plugins/database.ts +180 -180
- package/core/server/plugins/static-files-plugin.ts +69 -69
- package/core/server/plugins/swagger.ts +1 -1
- package/core/server/rooms/RoomBroadcaster.ts +357 -0
- package/core/server/rooms/RoomSystem.ts +463 -0
- package/core/server/rooms/index.ts +13 -0
- package/core/server/services/BaseService.ts +1 -1
- package/core/server/services/ServiceContainer.ts +1 -1
- package/core/server/services/index.ts +8 -8
- package/core/templates/create-project.ts +12 -12
- package/core/testing/index.ts +9 -9
- package/core/testing/setup.ts +73 -73
- package/core/types/api.ts +168 -168
- package/core/types/build.ts +219 -219
- package/core/types/config.ts +56 -26
- package/core/types/index.ts +4 -4
- package/core/types/plugin.ts +107 -107
- package/core/types/types.ts +353 -14
- package/core/utils/build-logger.ts +324 -324
- package/core/utils/config-schema.ts +480 -480
- package/core/utils/env.ts +2 -8
- package/core/utils/errors/codes.ts +114 -114
- package/core/utils/errors/handlers.ts +36 -1
- package/core/utils/errors/index.ts +49 -5
- package/core/utils/errors/middleware.ts +113 -113
- package/core/utils/helpers.ts +6 -16
- package/core/utils/index.ts +17 -17
- package/core/utils/logger/colors.ts +114 -114
- package/core/utils/logger/config.ts +13 -9
- package/core/utils/logger/formatter.ts +82 -82
- package/core/utils/logger/group-logger.ts +101 -101
- package/core/utils/logger/index.ts +6 -1
- package/core/utils/logger/stack-trace.ts +3 -1
- package/core/utils/logger/startup-banner.ts +82 -82
- package/core/utils/logger/winston-logger.ts +152 -152
- package/core/utils/monitoring/index.ts +211 -211
- package/core/utils/sync-version.ts +66 -66
- package/core/utils/version.ts +1 -1
- package/create-fluxstack.ts +8 -7
- package/package.json +12 -13
- package/plugins/crypto-auth/cli/make-protected-route.command.ts +1 -1
- package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -302
- package/plugins/crypto-auth/client/components/index.ts +11 -11
- package/plugins/crypto-auth/client/index.ts +11 -11
- package/plugins/crypto-auth/config/index.ts +1 -1
- package/plugins/crypto-auth/index.ts +4 -4
- package/plugins/crypto-auth/package.json +65 -65
- package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
- package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
- package/plugins/crypto-auth/server/index.ts +21 -21
- package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +3 -3
- package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +1 -1
- package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +2 -2
- package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +2 -2
- package/plugins/crypto-auth/server/middlewares/helpers.ts +1 -1
- package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
- package/tsconfig.api-strict.json +16 -0
- package/tsconfig.json +48 -52
- package/{app/client/tsconfig.node.json → tsconfig.node.json} +25 -25
- package/types/global.d.ts +29 -29
- package/types/vitest.d.ts +8 -8
- package/vite.config.ts +38 -62
- package/vitest.config.live.ts +10 -9
- package/vitest.config.ts +29 -17
- package/app/client/README.md +0 -69
- package/app/client/SIMPLIFICATION.md +0 -140
- package/app/client/frontend-only.ts +0 -12
- package/app/client/src/live/FileUploadExample.tsx +0 -359
- package/app/client/src/live/MinimalLiveClock.tsx +0 -47
- package/app/client/src/live/QuickUploadTest.tsx +0 -193
- package/app/client/tsconfig.app.json +0 -45
- package/app/client/tsconfig.json +0 -7
- package/app/client/zustand-setup.md +0 -65
- package/app/server/backend-only.ts +0 -18
- package/app/server/live/LiveClockComponent.ts +0 -215
- package/app/server/live/LiveFileUploadComponent.ts +0 -77
- package/app/server/routes/env-test.ts +0 -110
- package/core/client/hooks/index.ts +0 -7
- package/core/client/hooks/useHybridLiveComponent.ts +0 -685
- package/core/client/hooks/useTypedLiveComponent.ts +0 -133
- package/core/client/hooks/useWebSocket.ts +0 -361
- package/core/config/env.ts +0 -546
- package/core/config/loader.ts +0 -522
- package/core/config/runtime-config.ts +0 -327
- package/core/config/validator.ts +0 -540
- package/core/server/backend-entry.ts +0 -51
- package/core/server/standalone.ts +0 -106
- package/core/utils/regenerate-files.ts +0 -69
- package/fluxstack.config.ts +0 -354
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
# 🎨 FluxStack Client - Simplified Version
|
|
2
|
-
|
|
3
|
-
This is a **simplified, single-page version** of the FluxStack client, inspired by the clean and modern design of Vite's landing page.
|
|
4
|
-
|
|
5
|
-
## 🚀 What Changed?
|
|
6
|
-
|
|
7
|
-
### ✅ **Kept (Essential)**
|
|
8
|
-
- ✅ **Eden Treaty** - Core type-safe API client
|
|
9
|
-
- ✅ **React 19** - Modern React with hooks
|
|
10
|
-
- ✅ **Vite 7** - Lightning-fast dev server
|
|
11
|
-
- ✅ **TailwindCSS** - Utility-first styling
|
|
12
|
-
- ✅ **TypeScript** - Full type safety
|
|
13
|
-
- ✅ **react-icons** - Icon library
|
|
14
|
-
|
|
15
|
-
### ❌ **Removed (Complexity)**
|
|
16
|
-
- ❌ **React Router** - No more multi-page routing
|
|
17
|
-
- ❌ **Zustand** - Removed complex state management (using simple `useState`)
|
|
18
|
-
- ❌ **Multiple Pages** - Consolidated into single page (Overview, Demo, HybridLive, ApiDocs, CryptoAuth)
|
|
19
|
-
- ❌ **Complex Error System** - Simplified error handling
|
|
20
|
-
- ❌ **Navigation System** - No more tabs and complex navigation
|
|
21
|
-
- ❌ **Detailed API Status Section** - Replaced with simple badge
|
|
22
|
-
- ❌ **Complex Live Component UIs** - Simplified to minimal clock display
|
|
23
|
-
|
|
24
|
-
### ✅ **Kept (Advanced Features)**
|
|
25
|
-
- ✅ **LiveComponents** - Live Clock provido via LiveComponent
|
|
26
|
-
- ✅ **LiveComponentsProvider** - Full real-time capabilities maintained
|
|
27
|
-
- ✅ **Hybrid Live Component** - Clock synced with server in real-time
|
|
28
|
-
|
|
29
|
-
## 📊 Comparison
|
|
30
|
-
|
|
31
|
-
| Metric | Before | After | Reduction |
|
|
32
|
-
|--------|--------|-------|-----------|
|
|
33
|
-
| **Files** | 43 | ~10 | **-76%** |
|
|
34
|
-
| **Components** | 11 | 2 | **-82%** |
|
|
35
|
-
| **Pages** | 5 | 1 | **-80%** |
|
|
36
|
-
| **Dependencies** | 27 | 19 | **-30%** |
|
|
37
|
-
| **Lines in App.tsx** | 331 | 213 | **-36%** |
|
|
38
|
-
| **Live Components** | 6 complex | 1 minimal | **-83%** |
|
|
39
|
-
|
|
40
|
-
## 🎯 What Does It Show?
|
|
41
|
-
|
|
42
|
-
The simplified client demonstrates:
|
|
43
|
-
|
|
44
|
-
1. **🎨 Minimalist Design** - Clean, centered design inspired by Next.js, React, and Vite
|
|
45
|
-
2. **⚡ Simple API Status** - Single badge showing API online/offline
|
|
46
|
-
3. **🚀 Core Features** - 4 feature cards highlighting main capabilities
|
|
47
|
-
4. **🕐 Live Clock** - Real LiveComponent synced with server in real-time
|
|
48
|
-
5. **📖 Quick Actions** - Direct links to API Docs, GitHub, and API Demo
|
|
49
|
-
6. **🔥 Clean but Powerful** - Minimalist UI with full real-time capabilities
|
|
50
|
-
|
|
51
|
-
## 📝 Structure
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
app/client/src/
|
|
55
|
-
├── App.tsx # Single-page application (213 lines)
|
|
56
|
-
│ # - AppContent component (main UI)
|
|
57
|
-
│ # - MinimalLiveClock component (LiveComponent)
|
|
58
|
-
│ # - LiveComponentsProvider wrapper
|
|
59
|
-
├── main.tsx # Entry point (simplified)
|
|
60
|
-
├── index.css # Minimal global styles
|
|
61
|
-
├── vite-env.d.ts # Vite type definitions
|
|
62
|
-
├── assets/ # Static assets
|
|
63
|
-
│ └── react.svg # React logo
|
|
64
|
-
└── lib/ # Core utilities
|
|
65
|
-
├── eden-api.ts # Eden Treaty API client
|
|
66
|
-
└── errors.ts # Error handling utilities
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
**Total files in src/**: 6 core files (vs 43+ before)
|
|
70
|
-
|
|
71
|
-
## 🎨 Design Philosophy
|
|
72
|
-
|
|
73
|
-
Inspired by **Next.js, React, and Vite landing pages**:
|
|
74
|
-
- Everything centered vertically and horizontally
|
|
75
|
-
- Large animated logo (fire icon with pulse animation)
|
|
76
|
-
- Minimal text, maximum impact
|
|
77
|
-
- Simple API status badge (online/offline)
|
|
78
|
-
- 4 feature cards in responsive grid
|
|
79
|
-
- **Live Clock via LiveComponent** - Real-time sync with server
|
|
80
|
-
- Clean action buttons at bottom
|
|
81
|
-
- No background blob animations (clean and fast)
|
|
82
|
-
- Mobile-first responsive design
|
|
83
|
-
- **Full Live Components support** - Maintains advanced real-time features
|
|
84
|
-
|
|
85
|
-
## 🔧 How to Use
|
|
86
|
-
|
|
87
|
-
```bash
|
|
88
|
-
# Start development server (backend + frontend)
|
|
89
|
-
bun run dev
|
|
90
|
-
|
|
91
|
-
# Frontend only
|
|
92
|
-
bun run dev:frontend
|
|
93
|
-
|
|
94
|
-
# Backend only
|
|
95
|
-
bun run dev:backend
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
The page will automatically show:
|
|
99
|
-
- ✅ **Green badge** - Backend is running and healthy
|
|
100
|
-
- ⚠️ **Yellow badge** - Checking backend status
|
|
101
|
-
- ❌ **Red badge** - Backend is offline
|
|
102
|
-
|
|
103
|
-
## 🎯 When to Use This Version?
|
|
104
|
-
|
|
105
|
-
**Use this ultra-simplified version when:**
|
|
106
|
-
- You want the cleanest possible presentation
|
|
107
|
-
- You're showcasing FluxStack to newcomers or investors
|
|
108
|
-
- You need a professional landing page
|
|
109
|
-
- You want maximum simplicity (like Next.js/React/Vite)
|
|
110
|
-
- You prefer minimalism over features
|
|
111
|
-
- You want fast loading and minimal JavaScript
|
|
112
|
-
|
|
113
|
-
**Use the full version when:**
|
|
114
|
-
- You need multiple pages/routes
|
|
115
|
-
- You require complex state management
|
|
116
|
-
- You want real-time features (WebSocket)
|
|
117
|
-
- You need complete demos (CRUD, Auth, etc.)
|
|
118
|
-
- You're building a full application with all features
|
|
119
|
-
|
|
120
|
-
## 💡 Future Enhancements (Optional)
|
|
121
|
-
|
|
122
|
-
If you want to extend this simplified version, consider adding:
|
|
123
|
-
- [ ] Simple counter demo using Eden Treaty
|
|
124
|
-
- [ ] User CRUD with minimal UI
|
|
125
|
-
- [ ] Dark/Light theme toggle
|
|
126
|
-
- [ ] Smooth scroll to sections
|
|
127
|
-
- [ ] More feature cards
|
|
128
|
-
|
|
129
|
-
## 📚 References
|
|
130
|
-
|
|
131
|
-
- [FluxStack Documentation](../../ai-context/)
|
|
132
|
-
- [Eden Treaty Guide](../../ai-context/development/eden-treaty-guide.md)
|
|
133
|
-
- [Vite Documentation](https://vite.dev)
|
|
134
|
-
- [React Documentation](https://react.dev)
|
|
135
|
-
|
|
136
|
-
---
|
|
137
|
-
|
|
138
|
-
**🎯 Goal**: Provide a clean, simple, and beautiful client that showcases FluxStack's core value proposition without overwhelming complexity.
|
|
139
|
-
|
|
140
|
-
**Made with ❤️ by FluxStack Team**
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// Frontend standalone entry point
|
|
2
|
-
import { startFrontendOnly } from "@/core/client/standalone"
|
|
3
|
-
|
|
4
|
-
// Configuração para frontend standalone
|
|
5
|
-
const frontendConfig = {
|
|
6
|
-
clientPath: "app/client",
|
|
7
|
-
vitePort: (globalThis as any).process?.env?.FRONTEND_PORT || 5173,
|
|
8
|
-
apiUrl: (globalThis as any).process?.env?.API_URL || "http://localhost:3001"
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
// Iniciar apenas o frontend
|
|
12
|
-
startFrontendOnly(frontendConfig)
|
|
@@ -1,359 +0,0 @@
|
|
|
1
|
-
// 📤 File Upload Example - Demonstrates chunked file upload with Live Components
|
|
2
|
-
import { useState, useRef } from 'react'
|
|
3
|
-
import { useTypedLiveComponent, useChunkedUpload, useLiveComponents } from '@/core/client'
|
|
4
|
-
|
|
5
|
-
// Import component type DIRECTLY from backend - full type inference!
|
|
6
|
-
import type { LiveFileUploadComponent } from '@/server/live/LiveFileUploadComponent'
|
|
7
|
-
|
|
8
|
-
export function FileUploadExample() {
|
|
9
|
-
const fileInputRef = useRef<HTMLInputElement>(null)
|
|
10
|
-
const [selectedFile, setSelectedFile] = useState<File | null>(null)
|
|
11
|
-
|
|
12
|
-
// Get sendMessageAndWait from LiveComponents context
|
|
13
|
-
const { sendMessageAndWait } = useLiveComponents()
|
|
14
|
-
|
|
15
|
-
// Setup Live Component with full type inference
|
|
16
|
-
const {
|
|
17
|
-
state,
|
|
18
|
-
call,
|
|
19
|
-
componentId,
|
|
20
|
-
connected
|
|
21
|
-
} = useTypedLiveComponent<LiveFileUploadComponent>('LiveFileUpload', {
|
|
22
|
-
uploadedFiles: [],
|
|
23
|
-
maxFiles: 10
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
// Setup Chunked Upload Hook with Adaptive Chunking
|
|
27
|
-
const {
|
|
28
|
-
uploading,
|
|
29
|
-
progress,
|
|
30
|
-
error: uploadError,
|
|
31
|
-
uploadFile,
|
|
32
|
-
cancelUpload,
|
|
33
|
-
reset: resetUpload,
|
|
34
|
-
bytesUploaded,
|
|
35
|
-
totalBytes
|
|
36
|
-
} = useChunkedUpload(componentId || '', {
|
|
37
|
-
chunkSize: 64 * 1024, // 64KB initial chunk size
|
|
38
|
-
maxFileSize: 500 * 1024 * 1024, // 500MB max (aceita qualquer arquivo)
|
|
39
|
-
allowedTypes: [], // Aceita todos os tipos de arquivo
|
|
40
|
-
sendMessageAndWait,
|
|
41
|
-
|
|
42
|
-
// Enable Adaptive Chunking for optimal upload speed
|
|
43
|
-
adaptiveChunking: true,
|
|
44
|
-
adaptiveConfig: {
|
|
45
|
-
minChunkSize: 16 * 1024, // 16KB minimum
|
|
46
|
-
maxChunkSize: 512 * 1024, // 512KB maximum (safer for web)
|
|
47
|
-
initialChunkSize: 64 * 1024, // 64KB start
|
|
48
|
-
targetLatency: 200, // Target 200ms per chunk
|
|
49
|
-
adjustmentFactor: 1.5, // Moderate adjustment
|
|
50
|
-
measurementWindow: 3 // Measure last 3 chunks
|
|
51
|
-
},
|
|
52
|
-
|
|
53
|
-
onProgress: (progress, uploaded, total) => {
|
|
54
|
-
console.log(`📤 Upload progress: ${progress.toFixed(1)}% (${uploaded}/${total} bytes)`)
|
|
55
|
-
},
|
|
56
|
-
|
|
57
|
-
onComplete: async (response) => {
|
|
58
|
-
console.log('✅ Upload complete:', response)
|
|
59
|
-
|
|
60
|
-
// Notify the Live Component about the successful upload
|
|
61
|
-
if (selectedFile && response.fileUrl) {
|
|
62
|
-
await call('onFileUploaded', {
|
|
63
|
-
filename: selectedFile.name,
|
|
64
|
-
fileUrl: response.fileUrl
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Reset state
|
|
69
|
-
setSelectedFile(null)
|
|
70
|
-
resetUpload()
|
|
71
|
-
if (fileInputRef.current) {
|
|
72
|
-
fileInputRef.current.value = ''
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
|
|
76
|
-
onError: (error) => {
|
|
77
|
-
console.error('❌ Upload error:', error)
|
|
78
|
-
}
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
82
|
-
const file = e.target.files?.[0]
|
|
83
|
-
if (file) {
|
|
84
|
-
setSelectedFile(file)
|
|
85
|
-
resetUpload()
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const handleUpload = async () => {
|
|
90
|
-
if (!selectedFile) return
|
|
91
|
-
await uploadFile(selectedFile)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const handleRemoveFile = async (fileId: string) => {
|
|
95
|
-
await call('removeFile', { fileId })
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const handleClearAll = async () => {
|
|
99
|
-
await call('clearAll', {})
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const formatBytes = (bytes: number): string => {
|
|
103
|
-
if (bytes === 0) return '0 Bytes'
|
|
104
|
-
const k = 1024
|
|
105
|
-
const sizes = ['Bytes', 'KB', 'MB', 'GB']
|
|
106
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
107
|
-
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i]
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const getFileIcon = (filename: string): string => {
|
|
111
|
-
const ext = filename.toLowerCase().substring(filename.lastIndexOf('.'))
|
|
112
|
-
const iconMap: Record<string, string> = {
|
|
113
|
-
'.pdf': '📄',
|
|
114
|
-
'.doc': '📝',
|
|
115
|
-
'.docx': '📝',
|
|
116
|
-
'.xls': '📊',
|
|
117
|
-
'.xlsx': '📊',
|
|
118
|
-
'.ppt': '📽️',
|
|
119
|
-
'.pptx': '📽️',
|
|
120
|
-
'.zip': '🗜️',
|
|
121
|
-
'.rar': '🗜️',
|
|
122
|
-
'.7z': '🗜️',
|
|
123
|
-
'.jpg': '🖼️',
|
|
124
|
-
'.jpeg': '🖼️',
|
|
125
|
-
'.png': '🖼️',
|
|
126
|
-
'.gif': '🖼️',
|
|
127
|
-
'.webp': '🖼️',
|
|
128
|
-
'.mp4': '🎥',
|
|
129
|
-
'.avi': '🎥',
|
|
130
|
-
'.mov': '🎥',
|
|
131
|
-
'.mp3': '🎵',
|
|
132
|
-
'.wav': '🎵',
|
|
133
|
-
'.jar': '☕',
|
|
134
|
-
'.java': '☕',
|
|
135
|
-
'.js': '📜',
|
|
136
|
-
'.ts': '📜',
|
|
137
|
-
'.json': '📋',
|
|
138
|
-
'.xml': '📋',
|
|
139
|
-
'.txt': '📃',
|
|
140
|
-
'.md': '📰'
|
|
141
|
-
}
|
|
142
|
-
return iconMap[ext] || '📎'
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const isImageFile = (filename: string): boolean => {
|
|
146
|
-
const ext = filename.toLowerCase().substring(filename.lastIndexOf('.'))
|
|
147
|
-
return ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg', '.bmp'].includes(ext)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (!connected) {
|
|
151
|
-
return (
|
|
152
|
-
<div className="p-6 bg-yellow-50 border border-yellow-200 rounded-lg">
|
|
153
|
-
<p className="text-yellow-800">🔌 Connecting to Live Components...</p>
|
|
154
|
-
</div>
|
|
155
|
-
)
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const remainingSlots = state.maxFiles - state.uploadedFiles.length
|
|
159
|
-
|
|
160
|
-
return (
|
|
161
|
-
<div className="max-w-4xl mx-auto p-6">
|
|
162
|
-
<div className="bg-white rounded-lg shadow-lg">
|
|
163
|
-
{/* Header */}
|
|
164
|
-
<div className="p-6 border-b border-gray-200">
|
|
165
|
-
<h2 className="text-2xl font-bold text-gray-900">
|
|
166
|
-
📤 Universal File Upload
|
|
167
|
-
</h2>
|
|
168
|
-
<p className="mt-2 text-gray-600">
|
|
169
|
-
Upload any type of file with real-time progress tracking and adaptive chunking
|
|
170
|
-
</p>
|
|
171
|
-
</div>
|
|
172
|
-
|
|
173
|
-
{/* Upload Section */}
|
|
174
|
-
<div className="p-6 border-b border-gray-200">
|
|
175
|
-
<div className="space-y-4">
|
|
176
|
-
{/* File Input */}
|
|
177
|
-
<div>
|
|
178
|
-
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
179
|
-
Select Any File
|
|
180
|
-
</label>
|
|
181
|
-
<input
|
|
182
|
-
ref={fileInputRef}
|
|
183
|
-
type="file"
|
|
184
|
-
onChange={handleFileSelect}
|
|
185
|
-
disabled={uploading || remainingSlots === 0}
|
|
186
|
-
className="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100 disabled:opacity-50"
|
|
187
|
-
/>
|
|
188
|
-
<p className="mt-1 text-xs text-gray-500">
|
|
189
|
-
Maximum file size: 500 MB • All file types supported
|
|
190
|
-
</p>
|
|
191
|
-
</div>
|
|
192
|
-
|
|
193
|
-
{/* Selected File Info */}
|
|
194
|
-
{selectedFile && !uploading && (
|
|
195
|
-
<div className="p-4 bg-gray-50 rounded-lg">
|
|
196
|
-
<p className="text-sm text-gray-700">
|
|
197
|
-
<strong>Selected:</strong> {getFileIcon(selectedFile.name)} {selectedFile.name} ({formatBytes(selectedFile.size)})
|
|
198
|
-
</p>
|
|
199
|
-
</div>
|
|
200
|
-
)}
|
|
201
|
-
|
|
202
|
-
{/* Upload Progress */}
|
|
203
|
-
{uploading && (
|
|
204
|
-
<div className="space-y-2">
|
|
205
|
-
<div className="flex justify-between text-sm text-gray-600">
|
|
206
|
-
<span>Uploading {selectedFile?.name}...</span>
|
|
207
|
-
<span>{progress.toFixed(1)}%</span>
|
|
208
|
-
</div>
|
|
209
|
-
<div className="w-full bg-gray-200 rounded-full h-2.5">
|
|
210
|
-
<div
|
|
211
|
-
className="bg-blue-600 h-2.5 rounded-full transition-all duration-300"
|
|
212
|
-
style={{ width: `${progress}%` }}
|
|
213
|
-
/>
|
|
214
|
-
</div>
|
|
215
|
-
<p className="text-xs text-gray-500">
|
|
216
|
-
{formatBytes(bytesUploaded)} / {formatBytes(totalBytes)}
|
|
217
|
-
</p>
|
|
218
|
-
</div>
|
|
219
|
-
)}
|
|
220
|
-
|
|
221
|
-
{/* Error Display */}
|
|
222
|
-
{uploadError && (
|
|
223
|
-
<div className="p-4 bg-red-50 border border-red-200 rounded-lg">
|
|
224
|
-
<p className="text-sm text-red-800">❌ {uploadError}</p>
|
|
225
|
-
</div>
|
|
226
|
-
)}
|
|
227
|
-
|
|
228
|
-
{/* Action Buttons */}
|
|
229
|
-
<div className="flex gap-2">
|
|
230
|
-
<button
|
|
231
|
-
onClick={handleUpload}
|
|
232
|
-
disabled={!selectedFile || uploading || remainingSlots === 0}
|
|
233
|
-
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed font-medium"
|
|
234
|
-
>
|
|
235
|
-
{uploading ? '⏳ Uploading...' : '📤 Upload'}
|
|
236
|
-
</button>
|
|
237
|
-
|
|
238
|
-
{uploading && (
|
|
239
|
-
<button
|
|
240
|
-
onClick={cancelUpload}
|
|
241
|
-
className="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 font-medium"
|
|
242
|
-
>
|
|
243
|
-
❌ Cancel
|
|
244
|
-
</button>
|
|
245
|
-
)}
|
|
246
|
-
|
|
247
|
-
{state.uploadedFiles.length > 0 && (
|
|
248
|
-
<button
|
|
249
|
-
onClick={handleClearAll}
|
|
250
|
-
disabled={uploading}
|
|
251
|
-
className="px-4 py-2 bg-gray-600 text-white rounded-md hover:bg-gray-700 disabled:opacity-50 font-medium ml-auto"
|
|
252
|
-
>
|
|
253
|
-
🗑️ Clear All
|
|
254
|
-
</button>
|
|
255
|
-
)}
|
|
256
|
-
</div>
|
|
257
|
-
|
|
258
|
-
{/* Slots Info */}
|
|
259
|
-
<div className="text-sm text-gray-600">
|
|
260
|
-
{remainingSlots > 0 ? (
|
|
261
|
-
<span>✅ {remainingSlots} upload slot(s) remaining</span>
|
|
262
|
-
) : (
|
|
263
|
-
<span className="text-red-600">⚠️ Maximum files reached</span>
|
|
264
|
-
)}
|
|
265
|
-
</div>
|
|
266
|
-
</div>
|
|
267
|
-
</div>
|
|
268
|
-
|
|
269
|
-
{/* Uploaded Files Grid */}
|
|
270
|
-
<div className="p-6">
|
|
271
|
-
<h3 className="text-lg font-semibold text-gray-900 mb-4">
|
|
272
|
-
Uploaded Files ({state.uploadedFiles.length}/{state.maxFiles})
|
|
273
|
-
</h3>
|
|
274
|
-
|
|
275
|
-
{state.uploadedFiles.length === 0 ? (
|
|
276
|
-
<div className="text-center py-12 bg-gray-50 rounded-lg">
|
|
277
|
-
<p className="text-gray-500">No files uploaded yet</p>
|
|
278
|
-
</div>
|
|
279
|
-
) : (
|
|
280
|
-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
281
|
-
{state.uploadedFiles.map((file) => (
|
|
282
|
-
<div
|
|
283
|
-
key={file.id}
|
|
284
|
-
className="relative bg-white border border-gray-200 rounded-lg overflow-hidden hover:shadow-lg transition-shadow"
|
|
285
|
-
>
|
|
286
|
-
{/* File Preview */}
|
|
287
|
-
<div className="aspect-video bg-gray-100 flex items-center justify-center">
|
|
288
|
-
{isImageFile(file.filename) ? (
|
|
289
|
-
<img
|
|
290
|
-
src={file.url}
|
|
291
|
-
alt={file.filename}
|
|
292
|
-
className="max-w-full max-h-full object-contain"
|
|
293
|
-
onError={(e) => {
|
|
294
|
-
const target = e.target as HTMLImageElement
|
|
295
|
-
target.style.display = 'none'
|
|
296
|
-
target.parentElement!.innerHTML = `<div class="text-6xl">${getFileIcon(file.filename)}</div>`
|
|
297
|
-
}}
|
|
298
|
-
/>
|
|
299
|
-
) : (
|
|
300
|
-
<div className="text-6xl">{getFileIcon(file.filename)}</div>
|
|
301
|
-
)}
|
|
302
|
-
</div>
|
|
303
|
-
|
|
304
|
-
{/* Info */}
|
|
305
|
-
<div className="p-3">
|
|
306
|
-
<p className="text-sm font-medium text-gray-900 truncate" title={file.filename}>
|
|
307
|
-
{file.filename}
|
|
308
|
-
</p>
|
|
309
|
-
<p className="text-xs text-gray-500">
|
|
310
|
-
{new Date(file.uploadedAt).toLocaleString()}
|
|
311
|
-
</p>
|
|
312
|
-
<a
|
|
313
|
-
href={file.url}
|
|
314
|
-
target="_blank"
|
|
315
|
-
rel="noopener noreferrer"
|
|
316
|
-
className="text-xs text-blue-600 hover:underline mt-1 inline-block"
|
|
317
|
-
>
|
|
318
|
-
Download
|
|
319
|
-
</a>
|
|
320
|
-
</div>
|
|
321
|
-
|
|
322
|
-
{/* Remove Button */}
|
|
323
|
-
<button
|
|
324
|
-
onClick={() => handleRemoveFile(file.id)}
|
|
325
|
-
className="absolute top-2 right-2 p-2 bg-red-600 text-white rounded-full hover:bg-red-700 transition-colors shadow-lg"
|
|
326
|
-
title="Remove file"
|
|
327
|
-
>
|
|
328
|
-
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
|
|
329
|
-
<path
|
|
330
|
-
fillRule="evenodd"
|
|
331
|
-
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
|
|
332
|
-
clipRule="evenodd"
|
|
333
|
-
/>
|
|
334
|
-
</svg>
|
|
335
|
-
</button>
|
|
336
|
-
</div>
|
|
337
|
-
))}
|
|
338
|
-
</div>
|
|
339
|
-
)}
|
|
340
|
-
</div>
|
|
341
|
-
</div>
|
|
342
|
-
|
|
343
|
-
{/* Technical Info */}
|
|
344
|
-
<div className="mt-6 p-4 bg-gray-50 rounded-lg border border-gray-200">
|
|
345
|
-
<h4 className="font-semibold text-gray-900 mb-2">📋 Technical Details</h4>
|
|
346
|
-
<ul className="text-sm text-gray-600 space-y-1">
|
|
347
|
-
<li>✅ <strong>Adaptive Chunking:</strong> Enabled (16KB - 512KB)</li>
|
|
348
|
-
<li>✅ <strong>Initial Chunk Size:</strong> 64KB</li>
|
|
349
|
-
<li>✅ <strong>Max File Size:</strong> 500MB</li>
|
|
350
|
-
<li>✅ <strong>Allowed Types:</strong> All file types supported</li>
|
|
351
|
-
<li>✅ <strong>Real-time Progress:</strong> Shows bytes uploaded and percentage</li>
|
|
352
|
-
<li>✅ <strong>State Sync:</strong> Uploaded files synced via Live Component</li>
|
|
353
|
-
<li>✅ <strong>Component ID:</strong> {componentId || 'Not connected'}</li>
|
|
354
|
-
<li>🚀 <strong>Optimization:</strong> Chunk size adjusts based on connection speed</li>
|
|
355
|
-
</ul>
|
|
356
|
-
</div>
|
|
357
|
-
</div>
|
|
358
|
-
)
|
|
359
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
// 🔥 MinimalLiveClock - Live Component
|
|
2
|
-
import { useTypedLiveComponent } from '@/core/client';
|
|
3
|
-
|
|
4
|
-
// Import component type DIRECTLY from backend - full type inference!
|
|
5
|
-
import type { LiveClockComponent } from '@/server/live/LiveClockComponent';
|
|
6
|
-
|
|
7
|
-
export function MinimalLiveClock() {
|
|
8
|
-
const { state, setValue } = useTypedLiveComponent<LiveClockComponent>(
|
|
9
|
-
'LiveClock',
|
|
10
|
-
{
|
|
11
|
-
currentTime: "Loading...",
|
|
12
|
-
timeZone: "America/Sao_Paulo",
|
|
13
|
-
format: "12h",
|
|
14
|
-
showSeconds: true,
|
|
15
|
-
showDate: true,
|
|
16
|
-
lastSync: new Date(),
|
|
17
|
-
serverUptime: 0,
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
// Called when WebSocket connects (component not mounted yet - can't use setValue)
|
|
21
|
-
onConnect: () => {
|
|
22
|
-
console.log('onConnect called - WebSocket connected')
|
|
23
|
-
},
|
|
24
|
-
// Called after fresh mount (no prior state)
|
|
25
|
-
onMount: () => {
|
|
26
|
-
console.log('onMount called - changing format to 12h')
|
|
27
|
-
setValue('format', '12h')
|
|
28
|
-
},
|
|
29
|
-
// Called after successful rehydration (restoring prior state)
|
|
30
|
-
onRehydrate: () => {
|
|
31
|
-
console.log('onRehydrate called - keeping format 24h')
|
|
32
|
-
setValue('format', '24h')
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
return (
|
|
38
|
-
<div className="bg-gradient-to-br from-blue-500/10 to-purple-500/10 rounded-xl p-4 border border-blue-400/20">
|
|
39
|
-
<div className="text-4xl font-mono font-bold text-white text-center tracking-wider">
|
|
40
|
-
{state.currentTime}
|
|
41
|
-
</div>
|
|
42
|
-
<div className="text-center mt-2">
|
|
43
|
-
<span className="text-xs text-gray-400">{state.timeZone} ({state.format})</span>
|
|
44
|
-
</div>
|
|
45
|
-
</div>
|
|
46
|
-
)
|
|
47
|
-
}
|