create-fluxstack 1.8.3 → 1.10.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.
Files changed (52) hide show
  1. package/LIVE_COMPONENTS_REVIEW.md +781 -0
  2. package/README.md +653 -275
  3. package/app/client/src/App.tsx +39 -43
  4. package/app/client/src/lib/eden-api.ts +2 -7
  5. package/app/client/src/live/FileUploadExample.tsx +359 -0
  6. package/app/client/src/live/MinimalLiveClock.tsx +47 -0
  7. package/app/client/src/live/QuickUploadTest.tsx +193 -0
  8. package/app/client/src/main.tsx +10 -10
  9. package/app/client/src/vite-env.d.ts +1 -1
  10. package/app/client/tsconfig.app.json +45 -44
  11. package/app/client/tsconfig.node.json +25 -25
  12. package/app/server/index.ts +30 -103
  13. package/app/server/live/LiveFileUploadComponent.ts +77 -0
  14. package/app/server/live/register-components.ts +19 -19
  15. package/core/build/bundler.ts +202 -55
  16. package/core/build/index.ts +126 -2
  17. package/core/build/live-components-generator.ts +68 -1
  18. package/core/cli/generators/plugin.ts +6 -6
  19. package/core/cli/index.ts +232 -4
  20. package/core/client/LiveComponentsProvider.tsx +3 -9
  21. package/core/client/hooks/AdaptiveChunkSizer.ts +215 -0
  22. package/core/client/hooks/useChunkedUpload.ts +112 -61
  23. package/core/client/hooks/useHybridLiveComponent.ts +80 -26
  24. package/core/client/hooks/useTypedLiveComponent.ts +133 -0
  25. package/core/client/hooks/useWebSocket.ts +4 -16
  26. package/core/client/index.ts +20 -2
  27. package/core/framework/server.ts +181 -8
  28. package/core/live/ComponentRegistry.ts +5 -1
  29. package/core/plugins/built-in/index.ts +8 -5
  30. package/core/plugins/built-in/live-components/commands/create-live-component.ts +55 -63
  31. package/core/plugins/built-in/vite/index.ts +75 -187
  32. package/core/plugins/built-in/vite/vite-dev.ts +88 -0
  33. package/core/plugins/registry.ts +54 -2
  34. package/core/plugins/types.ts +86 -2
  35. package/core/server/index.ts +1 -2
  36. package/core/server/live/ComponentRegistry.ts +14 -5
  37. package/core/server/live/FileUploadManager.ts +22 -25
  38. package/core/server/live/auto-generated-components.ts +29 -26
  39. package/core/server/live/websocket-plugin.ts +19 -5
  40. package/core/server/plugins/static-files-plugin.ts +49 -240
  41. package/core/server/plugins/swagger.ts +33 -33
  42. package/core/types/build.ts +22 -0
  43. package/core/types/plugin.ts +9 -1
  44. package/core/types/types.ts +137 -0
  45. package/core/utils/logger/startup-banner.ts +20 -4
  46. package/core/utils/version.ts +6 -6
  47. package/create-fluxstack.ts +7 -7
  48. package/eslint.config.js +23 -23
  49. package/package.json +3 -2
  50. package/plugins/crypto-auth/server/middlewares.ts +19 -19
  51. package/tsconfig.json +52 -51
  52. package/workspace.json +5 -5
@@ -0,0 +1,193 @@
1
+ // 🚀 Quick Upload Test - Compact upload tester for home page
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 QuickUploadTest() {
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 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,
38
+ maxFileSize: 500 * 1024 * 1024,
39
+ allowedTypes: [], // Aceita todos os tipos
40
+ sendMessageAndWait,
41
+
42
+ // Enable Adaptive Chunking
43
+ adaptiveChunking: true,
44
+ adaptiveConfig: {
45
+ minChunkSize: 16 * 1024,
46
+ maxChunkSize: 512 * 1024,
47
+ initialChunkSize: 64 * 1024,
48
+ targetLatency: 200,
49
+ adjustmentFactor: 1.5,
50
+ measurementWindow: 3
51
+ },
52
+
53
+ onComplete: async (response) => {
54
+ if (selectedFile && response.fileUrl) {
55
+ await call('onFileUploaded', {
56
+ filename: selectedFile.name,
57
+ fileUrl: response.fileUrl
58
+ })
59
+ }
60
+ setSelectedFile(null)
61
+ resetUpload()
62
+ if (fileInputRef.current) {
63
+ fileInputRef.current.value = ''
64
+ }
65
+ },
66
+
67
+ onError: (error) => {
68
+ console.error('Upload error:', error)
69
+ }
70
+ })
71
+
72
+ const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
73
+ const file = e.target.files?.[0]
74
+ if (file) {
75
+ setSelectedFile(file)
76
+ resetUpload()
77
+ }
78
+ }
79
+
80
+ const handleUpload = async () => {
81
+ if (!selectedFile) return
82
+ await uploadFile(selectedFile)
83
+ }
84
+
85
+ const formatBytes = (bytes: number): string => {
86
+ if (bytes === 0) return '0 B'
87
+ const k = 1024
88
+ const sizes = ['B', 'KB', 'MB']
89
+ const i = Math.floor(Math.log(bytes) / Math.log(k))
90
+ return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i]
91
+ }
92
+
93
+ if (!connected) {
94
+ return (
95
+ <div className="bg-white/5 backdrop-blur-sm border border-white/10 rounded-2xl p-6">
96
+ <div className="text-yellow-400 text-sm">🔌 Connecting...</div>
97
+ </div>
98
+ )
99
+ }
100
+
101
+ return (
102
+ <div className="bg-white/5 backdrop-blur-sm border border-white/10 rounded-2xl p-6 hover:bg-white/10 transition-all">
103
+ <div className="flex items-center gap-3 mb-4">
104
+ <div className="text-3xl">📤</div>
105
+ <div>
106
+ <h3 className="text-lg font-semibold text-white">Adaptive Upload Test</h3>
107
+ <p className="text-xs text-gray-400">Dynamic chunk sizing enabled</p>
108
+ </div>
109
+ </div>
110
+
111
+ {/* File Input */}
112
+ <div className="space-y-3">
113
+ <input
114
+ ref={fileInputRef}
115
+ type="file"
116
+ onChange={handleFileSelect}
117
+ disabled={uploading}
118
+ className="block w-full text-sm text-gray-300 file:mr-3 file:py-2 file:px-4 file:rounded-lg file:border-0 file:text-sm file:font-semibold file:bg-purple-600 file:text-white hover:file:bg-purple-700 disabled:opacity-50 cursor-pointer"
119
+ />
120
+
121
+ {/* Selected File */}
122
+ {selectedFile && !uploading && (
123
+ <div className="text-sm text-gray-300">
124
+ 📁 {selectedFile.name} ({formatBytes(selectedFile.size)})
125
+ </div>
126
+ )}
127
+
128
+ {/* Upload Progress */}
129
+ {uploading && (
130
+ <div className="space-y-2">
131
+ <div className="flex justify-between text-xs text-gray-300">
132
+ <span>Uploading...</span>
133
+ <span>{progress.toFixed(1)}%</span>
134
+ </div>
135
+ <div className="w-full bg-gray-700 rounded-full h-2">
136
+ <div
137
+ className="bg-gradient-to-r from-blue-500 to-purple-600 h-2 rounded-full transition-all duration-300"
138
+ style={{ width: `${progress}%` }}
139
+ />
140
+ </div>
141
+ <div className="text-xs text-gray-400">
142
+ {formatBytes(bytesUploaded)} / {formatBytes(totalBytes)}
143
+ </div>
144
+ </div>
145
+ )}
146
+
147
+ {/* Error */}
148
+ {uploadError && (
149
+ <div className="text-xs text-red-400">❌ {uploadError}</div>
150
+ )}
151
+
152
+ {/* Buttons */}
153
+ <div className="flex gap-2">
154
+ <button
155
+ onClick={handleUpload}
156
+ disabled={!selectedFile || uploading}
157
+ className="flex-1 px-4 py-2 bg-gradient-to-r from-blue-500 to-purple-600 text-white rounded-lg hover:shadow-lg hover:shadow-purple-500/50 disabled:opacity-50 disabled:cursor-not-allowed font-medium text-sm transition-all"
158
+ >
159
+ {uploading ? '⏳ Uploading...' : '🚀 Upload'}
160
+ </button>
161
+
162
+ {uploading && (
163
+ <button
164
+ onClick={cancelUpload}
165
+ className="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 font-medium text-sm"
166
+ >
167
+
168
+ </button>
169
+ )}
170
+ </div>
171
+
172
+ {/* Last Upload Info */}
173
+ {state.uploadedFiles.length > 0 && !uploading && (
174
+ <div className="pt-3 border-t border-white/10">
175
+ <div className="text-xs text-green-400">
176
+ ✅ Last: {state.uploadedFiles[0].filename}
177
+ </div>
178
+ </div>
179
+ )}
180
+
181
+ {/* Quick Stats */}
182
+ <div className="pt-3 border-t border-white/10">
183
+ <div className="text-xs text-gray-400 space-y-1">
184
+ <div>🚀 Adaptive: 16KB - 512KB</div>
185
+ <div>📊 Target: 200ms/chunk</div>
186
+ <div>💾 Max: 500MB</div>
187
+ <div>📁 All file types</div>
188
+ </div>
189
+ </div>
190
+ </div>
191
+ </div>
192
+ )
193
+ }
@@ -1,10 +1,10 @@
1
- import { StrictMode } from 'react'
2
- import { createRoot } from 'react-dom/client'
3
- import './index.css'
4
- import App from './App.tsx'
5
-
6
- createRoot(document.getElementById('root')!).render(
7
- <StrictMode>
8
- <App />
9
- </StrictMode>,
10
- )
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import './index.css'
4
+ import App from './App.tsx'
5
+
6
+ createRoot(document.getElementById('root')!).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ )
@@ -1 +1 @@
1
- /// <reference types="vite/client" />
1
+ /// <reference types="vite/client" />
@@ -1,44 +1,45 @@
1
- {
2
- "compilerOptions": {
3
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
- "target": "ES2022",
5
- "useDefineForClassFields": true,
6
- "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
- "module": "ESNext",
8
- "skipLibCheck": true,
9
-
10
- /* Bundler mode */
11
- "moduleResolution": "bundler",
12
- "allowImportingTsExtensions": true,
13
- "verbatimModuleSyntax": true,
14
- "moduleDetection": "force",
15
- "noEmit": true,
16
- "jsx": "react-jsx",
17
-
18
- /* Path mapping (alias support) */
19
- "baseUrl": ".",
20
- "paths": {
21
- "@/*": ["./src/*"],
22
- "@/components/*": ["./src/components/*"],
23
- "@/utils/*": ["./src/utils/*"],
24
- "@/hooks/*": ["./src/hooks/*"],
25
- "@/assets/*": ["./src/assets/*"],
26
- "@/lib/*": ["./src/lib/*"],
27
- "@/types/*": ["./src/types/*"],
28
- "@/shared/*": ["../shared/*"],
29
- "@/core/*": ["../../core/*"],
30
- "@/config/*": ["../../config/*"],
31
- "fluxstack": ["../../core/client/fluxstack"],
32
- "elysia": ["../../node_modules/elysia"]
33
- },
34
-
35
- /* Linting */
36
- "strict": true,
37
- "noUnusedLocals": true,
38
- "noUnusedParameters": true,
39
- "erasableSyntaxOnly": true,
40
- "noFallthroughCasesInSwitch": true,
41
- "noUncheckedSideEffectImports": true
42
- },
43
- "include": ["src"]
44
- }
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
+ "target": "ES2022",
5
+ "useDefineForClassFields": true,
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "module": "ESNext",
8
+ "skipLibCheck": true,
9
+
10
+ /* Bundler mode */
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "verbatimModuleSyntax": true,
14
+ "moduleDetection": "force",
15
+ "noEmit": true,
16
+ "jsx": "react-jsx",
17
+
18
+ /* Path mapping (alias support) */
19
+ "baseUrl": ".",
20
+ "paths": {
21
+ "@/*": ["./src/*"],
22
+ "@/components/*": ["./src/components/*"],
23
+ "@/utils/*": ["./src/utils/*"],
24
+ "@/hooks/*": ["./src/hooks/*"],
25
+ "@/assets/*": ["./src/assets/*"],
26
+ "@/lib/*": ["./src/lib/*"],
27
+ "@/types/*": ["./src/types/*"],
28
+ "@/shared/*": ["../shared/*"],
29
+ "@/server/*": ["../server/*"],
30
+ "@/core/*": ["../../core/*"],
31
+ "@/config/*": ["../../config/*"],
32
+ "fluxstack": ["../../core/client/fluxstack"],
33
+ "elysia": ["../../node_modules/elysia"]
34
+ },
35
+
36
+ /* Linting */
37
+ "strict": true,
38
+ "noUnusedLocals": true,
39
+ "noUnusedParameters": true,
40
+ "erasableSyntaxOnly": true,
41
+ "noFallthroughCasesInSwitch": true,
42
+ "noUncheckedSideEffectImports": true
43
+ },
44
+ "include": ["src"]
45
+ }
@@ -1,25 +1,25 @@
1
- {
2
- "compilerOptions": {
3
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
- "target": "ES2023",
5
- "lib": ["ES2023"],
6
- "module": "ESNext",
7
- "skipLibCheck": true,
8
-
9
- /* Bundler mode */
10
- "moduleResolution": "bundler",
11
- "allowImportingTsExtensions": true,
12
- "verbatimModuleSyntax": true,
13
- "moduleDetection": "force",
14
- "noEmit": true,
15
-
16
- /* Linting */
17
- "strict": true,
18
- "noUnusedLocals": true,
19
- "noUnusedParameters": true,
20
- "erasableSyntaxOnly": true,
21
- "noFallthroughCasesInSwitch": true,
22
- "noUncheckedSideEffectImports": true
23
- },
24
- "include": ["vite.config.ts"]
25
- }
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "ES2023",
5
+ "lib": ["ES2023"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+
9
+ /* Bundler mode */
10
+ "moduleResolution": "bundler",
11
+ "allowImportingTsExtensions": true,
12
+ "verbatimModuleSyntax": true,
13
+ "moduleDetection": "force",
14
+ "noEmit": true,
15
+
16
+ /* Linting */
17
+ "strict": true,
18
+ "noUnusedLocals": true,
19
+ "noUnusedParameters": true,
20
+ "erasableSyntaxOnly": true,
21
+ "noFallthroughCasesInSwitch": true,
22
+ "noUncheckedSideEffectImports": true
23
+ },
24
+ "include": ["vite.config.ts"]
25
+ }
@@ -1,115 +1,42 @@
1
1
  /**
2
- * 🚀 FluxStack Application Server Entry Point
3
- * Main server configuration and initialization
2
+ * FluxStack Application Server Entry Point
4
3
  */
5
4
 
6
- // ===== Core Framework =====
5
+ // Core
7
6
  import { FluxStackFramework } from "@/core/server"
8
- import { isDevelopment } from "@/core/utils/helpers"
9
- import { DEBUG } from "@/core/utils/logger"
10
7
  import { helpers } from "@/core/utils/env"
11
-
12
- // ===== Configuration =====
13
8
  import { appConfig } from "@/config/app.config"
14
9
  import { serverConfig } from "@/config/server.config"
15
10
 
16
- // ===== Plugins =====
17
- import {
18
- vitePlugin,
19
- swaggerPlugin,
20
- staticPlugin,
21
- liveComponentsPlugin,
22
- staticFilesPlugin
23
- } from "@/core/server"
11
+ // Plugins
12
+ import { vitePlugin, swaggerPlugin, liveComponentsPlugin, staticFilesPlugin } from "@/core/server"
24
13
  import cryptoAuthPlugin from "@/plugins/crypto-auth"
25
-
26
- // ===== Application Routes =====
14
+ // Routes & Components
27
15
  import { appInstance } from "./app"
28
16
 
29
- // ===== Live Components Registration =====
30
- // Import auto-generated component registrations from core/ (for production build)
31
- // The generator creates this file in core/ to prevent accidental user modifications
32
- // This ensures components are registered before the plugin tries to use them
33
- import "@/core/server/live/auto-generated-components"
34
-
35
- // ===== Startup Logging =====
36
- DEBUG('🔧 Loading declarative configuration...')
37
- DEBUG(`📊 Environment: ${appConfig.env}`)
38
- DEBUG(`🚀 Port: ${serverConfig.server.port}`)
39
- DEBUG(`🌐 Host: ${serverConfig.server.host}`)
40
-
41
- // ===== Framework Configuration Helper =====
42
- /**
43
- * Creates FluxStack framework configuration from declarative configs
44
- */
45
- function createFrameworkConfig() {
46
- return {
47
- server: {
48
- port: serverConfig.server.port,
49
- host: serverConfig.server.host,
50
- apiPrefix: serverConfig.server.apiPrefix,
51
- cors: {
52
- origins: serverConfig.cors.origins,
53
- methods: serverConfig.cors.methods,
54
- headers: serverConfig.cors.headers,
55
- credentials: serverConfig.cors.credentials
56
- },
57
- middleware: []
58
- },
59
- app: {
60
- name: appConfig.name,
61
- version: appConfig.version
62
- },
63
- client: {
64
- port: serverConfig.server.backendPort,
65
- proxy: {
66
- target: helpers.getServerUrl()
67
- },
68
- build: {
69
- sourceMaps: false,
70
- minify: false,
71
- target: 'es2020' as any,
72
- outDir: 'dist'
73
- }
74
- }
17
+ // Server
18
+ const app = new FluxStackFramework({
19
+ server: {
20
+ ...serverConfig.server,
21
+ cors: serverConfig.cors,
22
+ middleware: []
23
+ },
24
+ app: {
25
+ name: appConfig.name,
26
+ version: appConfig.version
27
+ },
28
+ client: {
29
+ port: serverConfig.server.backendPort,
30
+ proxy: { target: helpers.getServerUrl() },
31
+ build: { sourceMaps: false, minify: false, target: 'es2020', outDir: 'dist' }
75
32
  }
76
- }
77
-
78
- // ===== Initialize Application =====
79
- const app = new FluxStackFramework(createFrameworkConfig())
80
-
81
- // ===== Register Plugins =====
82
- // Note: Logger is part of core, not a plugin
83
-
84
- // 1. Authentication plugin (must be registered first)
85
- app.use(cryptoAuthPlugin)
86
-
87
- // 2. Development/Production plugins (conditional)
88
- if (isDevelopment()) {
89
- app.use(vitePlugin) // Development: Vite dev server
90
- } else {
91
- app.use(staticPlugin) // Production: Static file serving
92
- }
93
-
94
- // 3. Static files (after Vite, before Live Components to avoid conflicts)
95
- app.use(staticFilesPlugin)
96
-
97
- // 4. Live Components (WebSocket support)
98
- app.use(liveComponentsPlugin)
99
-
100
- // ===== Register Routes =====
101
- // Note: Routes are now registered in app.ts (including envTestRoute)
102
- app.routes(appInstance)
103
-
104
- // ===== Final Setup =====
105
-
106
- // Swagger documentation (must be last to discover all routes)
107
- app.use(swaggerPlugin)
108
-
109
- // ===== Start Server =====
110
- // Banner will be displayed automatically by the framework
111
- app.listen()
112
-
113
- // ===== Eden Treaty Type Export =====
114
- // Export application type for type-safe client communication
115
- export type App = typeof app
33
+ })
34
+ .use(cryptoAuthPlugin)
35
+ .use(vitePlugin)
36
+ .use(staticFilesPlugin)
37
+ .use(liveComponentsPlugin)
38
+ .routes(appInstance)
39
+ .use(swaggerPlugin)
40
+ .listen()
41
+
42
+ export type App = typeof app
@@ -0,0 +1,77 @@
1
+ // 📤 Live File Upload Component - Universal file upload with chunking
2
+ import { LiveComponent } from '@/core/types/types'
3
+
4
+ interface FileUploadState {
5
+ uploadedFiles: Array<{
6
+ id: string
7
+ filename: string
8
+ url: string
9
+ uploadedAt: number
10
+ }>
11
+ maxFiles: number
12
+ }
13
+
14
+ export class LiveFileUploadComponent extends LiveComponent<FileUploadState> {
15
+ constructor(initialState: FileUploadState, ws: any, options?: { room?: string; userId?: string }) {
16
+ super({
17
+ uploadedFiles: [],
18
+ maxFiles: 10,
19
+ ...initialState
20
+ }, ws, options)
21
+ }
22
+
23
+ /**
24
+ * Handle successful file upload
25
+ * This is called from the client after useChunkedUpload completes
26
+ */
27
+ async onFileUploaded(payload: { filename: string; fileUrl: string }): Promise<void> {
28
+ const { filename, fileUrl } = payload
29
+
30
+ // Add new file to the list
31
+ const newFile = {
32
+ id: `file-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
33
+ filename,
34
+ url: fileUrl,
35
+ uploadedAt: Date.now()
36
+ }
37
+
38
+ // Limit to maxFiles
39
+ const updatedFiles = [newFile, ...this.state.uploadedFiles].slice(0, this.state.maxFiles)
40
+
41
+ // Update state and broadcast to all clients
42
+ this.setState({
43
+ uploadedFiles: updatedFiles
44
+ })
45
+ }
46
+
47
+ /**
48
+ * Remove an uploaded file
49
+ */
50
+ async removeFile(payload: { fileId: string }): Promise<void> {
51
+ this.setState({
52
+ uploadedFiles: this.state.uploadedFiles.filter(file => file.id !== payload.fileId)
53
+ })
54
+ }
55
+
56
+ /**
57
+ * Clear all uploaded files
58
+ */
59
+ async clearAll(): Promise<void> {
60
+ this.setState({
61
+ uploadedFiles: []
62
+ })
63
+ }
64
+
65
+ /**
66
+ * Get upload statistics
67
+ */
68
+ async getStats(): Promise<{
69
+ totalFiles: number
70
+ remainingSlots: number
71
+ }> {
72
+ return {
73
+ totalFiles: this.state.uploadedFiles.length,
74
+ remainingSlots: this.state.maxFiles - this.state.uploadedFiles.length
75
+ }
76
+ }
77
+ }
@@ -1,19 +1,19 @@
1
- // ⚠️ DEPRECATION NOTICE
2
- // This file has been moved to: core/server/live/auto-generated-components.ts
3
- //
4
- // The auto-generated component registration is now located in the core/ directory
5
- // to prevent accidental user modifications and keep framework code separate from
6
- // application code.
7
- //
8
- // If you're looking for component registration logic:
9
- // - Generated file: core/server/live/auto-generated-components.ts (auto-generated during build)
10
- // - Generator: core/build/live-components-generator.ts
11
- // - Import location: app/server/index.ts
12
- //
13
- // To add new Live Components:
14
- // 1. Create your component class in this directory (app/server/live/)
15
- // 2. Extend LiveComponent class
16
- // 3. Run 'bun run build' to regenerate the registration file
17
-
18
- // This file intentionally left empty - do not import
19
- export {}
1
+ // ⚠️ DEPRECATION NOTICE
2
+ // This file has been moved to: core/server/live/auto-generated-components.ts
3
+ //
4
+ // The auto-generated component registration is now located in the core/ directory
5
+ // to prevent accidental user modifications and keep framework code separate from
6
+ // application code.
7
+ //
8
+ // If you're looking for component registration logic:
9
+ // - Generated file: core/server/live/auto-generated-components.ts (auto-generated during build)
10
+ // - Generator: core/build/live-components-generator.ts
11
+ // - Import location: app/server/index.ts
12
+ //
13
+ // To add new Live Components:
14
+ // 1. Create your component class in this directory (app/server/live/)
15
+ // 2. Extend LiveComponent class
16
+ // 3. Run 'bun run build' to regenerate the registration file
17
+
18
+ // This file intentionally left empty - do not import
19
+ export {}