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
|
@@ -5,20 +5,50 @@ import type {
|
|
|
5
5
|
FileUploadChunkMessage,
|
|
6
6
|
FileUploadCompleteMessage,
|
|
7
7
|
FileUploadProgressResponse,
|
|
8
|
-
FileUploadCompleteResponse
|
|
9
|
-
|
|
8
|
+
FileUploadCompleteResponse,
|
|
9
|
+
BinaryChunkHeader
|
|
10
|
+
} from '@core/types/types'
|
|
10
11
|
|
|
11
12
|
export interface ChunkedUploadOptions {
|
|
12
13
|
chunkSize?: number // Default 64KB (used as initial if adaptive is enabled)
|
|
13
14
|
maxFileSize?: number // Default 50MB
|
|
14
15
|
allowedTypes?: string[]
|
|
15
|
-
sendMessageAndWait?: (message: any, timeout?: number) => Promise<any> // WebSocket send function
|
|
16
|
+
sendMessageAndWait?: (message: any, timeout?: number) => Promise<any> // WebSocket send function for JSON
|
|
17
|
+
sendBinaryAndWait?: (data: ArrayBuffer, requestId: string, timeout?: number) => Promise<any> // WebSocket send function for binary
|
|
16
18
|
onProgress?: (progress: number, bytesUploaded: number, totalBytes: number) => void
|
|
17
19
|
onComplete?: (response: FileUploadCompleteResponse) => void
|
|
18
20
|
onError?: (error: string) => void
|
|
19
21
|
// Adaptive chunking options
|
|
20
22
|
adaptiveChunking?: boolean // Enable adaptive chunk sizing (default: false)
|
|
21
23
|
adaptiveConfig?: Partial<AdaptiveChunkConfig> // Adaptive chunking configuration
|
|
24
|
+
// Binary protocol (more efficient, ~33% less data)
|
|
25
|
+
useBinaryProtocol?: boolean // Enable binary chunk protocol (default: true)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Creates a binary message with header + data
|
|
30
|
+
* Format: [4 bytes header length][JSON header][binary data]
|
|
31
|
+
*/
|
|
32
|
+
function createBinaryChunkMessage(header: BinaryChunkHeader, chunkData: Uint8Array): ArrayBuffer {
|
|
33
|
+
const headerJson = JSON.stringify(header)
|
|
34
|
+
const headerBytes = new TextEncoder().encode(headerJson)
|
|
35
|
+
|
|
36
|
+
// Total size: 4 bytes (header length) + header + data
|
|
37
|
+
const totalSize = 4 + headerBytes.length + chunkData.length
|
|
38
|
+
const buffer = new ArrayBuffer(totalSize)
|
|
39
|
+
const view = new DataView(buffer)
|
|
40
|
+
const uint8View = new Uint8Array(buffer)
|
|
41
|
+
|
|
42
|
+
// Write header length (little-endian)
|
|
43
|
+
view.setUint32(0, headerBytes.length, true)
|
|
44
|
+
|
|
45
|
+
// Write header
|
|
46
|
+
uint8View.set(headerBytes, 4)
|
|
47
|
+
|
|
48
|
+
// Write chunk data
|
|
49
|
+
uint8View.set(chunkData, 4 + headerBytes.length)
|
|
50
|
+
|
|
51
|
+
return buffer
|
|
22
52
|
}
|
|
23
53
|
|
|
24
54
|
export interface ChunkedUploadState {
|
|
@@ -46,13 +76,18 @@ export function useChunkedUpload(componentId: string, options: ChunkedUploadOpti
|
|
|
46
76
|
maxFileSize = 50 * 1024 * 1024, // 50MB default
|
|
47
77
|
allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp', 'image/gif'],
|
|
48
78
|
sendMessageAndWait,
|
|
79
|
+
sendBinaryAndWait,
|
|
49
80
|
onProgress,
|
|
50
81
|
onComplete,
|
|
51
82
|
onError,
|
|
52
83
|
adaptiveChunking = false,
|
|
53
|
-
adaptiveConfig
|
|
84
|
+
adaptiveConfig,
|
|
85
|
+
useBinaryProtocol = true // Default to binary for efficiency
|
|
54
86
|
} = options
|
|
55
87
|
|
|
88
|
+
// Determine if we can use binary protocol
|
|
89
|
+
const canUseBinary = useBinaryProtocol && sendBinaryAndWait
|
|
90
|
+
|
|
56
91
|
const abortControllerRef = useRef<AbortController | null>(null)
|
|
57
92
|
const adaptiveSizerRef = useRef<AdaptiveChunkSizer | null>(null)
|
|
58
93
|
|
|
@@ -60,7 +95,7 @@ export function useChunkedUpload(componentId: string, options: ChunkedUploadOpti
|
|
|
60
95
|
if (adaptiveChunking && !adaptiveSizerRef.current) {
|
|
61
96
|
adaptiveSizerRef.current = new AdaptiveChunkSizer({
|
|
62
97
|
initialChunkSize: chunkSize,
|
|
63
|
-
minChunkSize:
|
|
98
|
+
minChunkSize: chunkSize, // Do not go below initial chunk size by default
|
|
64
99
|
maxChunkSize: 1024 * 1024, // 1MB max
|
|
65
100
|
...adaptiveConfig
|
|
66
101
|
})
|
|
@@ -109,7 +144,8 @@ export function useChunkedUpload(componentId: string, options: ChunkedUploadOpti
|
|
|
109
144
|
uploadId,
|
|
110
145
|
filename: file.name,
|
|
111
146
|
size: file.size,
|
|
112
|
-
adaptiveChunking
|
|
147
|
+
adaptiveChunking,
|
|
148
|
+
protocol: canUseBinary ? 'binary' : 'base64'
|
|
113
149
|
})
|
|
114
150
|
|
|
115
151
|
// Reset adaptive sizer for new upload
|
|
@@ -141,50 +177,64 @@ export function useChunkedUpload(componentId: string, options: ChunkedUploadOpti
|
|
|
141
177
|
|
|
142
178
|
console.log('✅ Upload started successfully')
|
|
143
179
|
|
|
144
|
-
// Read file as ArrayBuffer for dynamic chunking
|
|
145
|
-
const fileArrayBuffer = await file.arrayBuffer()
|
|
146
|
-
const fileData = new Uint8Array(fileArrayBuffer)
|
|
147
|
-
|
|
148
180
|
let offset = 0
|
|
149
181
|
let chunkIndex = 0
|
|
150
182
|
const estimatedTotalChunks = Math.ceil(file.size / initialChunkSize)
|
|
151
183
|
|
|
152
|
-
// Send chunks dynamically with adaptive sizing
|
|
153
|
-
while (offset <
|
|
184
|
+
// Send chunks dynamically with adaptive sizing (read slice per chunk)
|
|
185
|
+
while (offset < file.size) {
|
|
154
186
|
if (abortControllerRef.current?.signal.aborted) {
|
|
155
187
|
throw new Error('Upload cancelled')
|
|
156
188
|
}
|
|
157
189
|
|
|
158
190
|
// Get current chunk size (adaptive or fixed)
|
|
159
191
|
const currentChunkSize = adaptiveSizerRef.current?.getChunkSize() ?? chunkSize
|
|
160
|
-
const chunkEnd = Math.min(offset + currentChunkSize,
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
// Convert chunk to base64
|
|
164
|
-
let binary = ''
|
|
165
|
-
for (let j = 0; j < chunkBytes.length; j++) {
|
|
166
|
-
binary += String.fromCharCode(chunkBytes[j])
|
|
167
|
-
}
|
|
168
|
-
const base64Chunk = btoa(binary)
|
|
192
|
+
const chunkEnd = Math.min(offset + currentChunkSize, file.size)
|
|
193
|
+
const sliceBuffer = await file.slice(offset, chunkEnd).arrayBuffer()
|
|
194
|
+
const chunkBytes = new Uint8Array(sliceBuffer)
|
|
169
195
|
|
|
170
196
|
// Record chunk start time for adaptive sizing
|
|
171
197
|
const chunkStartTime = adaptiveSizerRef.current?.recordChunkStart(chunkIndex) ?? 0
|
|
198
|
+
const requestId = `chunk-${uploadId}-${chunkIndex}`
|
|
172
199
|
|
|
173
|
-
|
|
174
|
-
type: 'FILE_UPLOAD_CHUNK',
|
|
175
|
-
componentId,
|
|
176
|
-
uploadId,
|
|
177
|
-
chunkIndex,
|
|
178
|
-
totalChunks: estimatedTotalChunks, // Approximate, will be recalculated
|
|
179
|
-
data: base64Chunk,
|
|
180
|
-
requestId: `chunk-${uploadId}-${chunkIndex}`
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
console.log(`📤 Sending chunk ${chunkIndex + 1} (size: ${chunkBytes.length} bytes)`)
|
|
200
|
+
console.log(`📤 Sending chunk ${chunkIndex + 1} (size: ${chunkBytes.length} bytes)${canUseBinary ? ' [binary]' : ' [base64]'}`)
|
|
184
201
|
|
|
185
202
|
try {
|
|
186
|
-
|
|
187
|
-
|
|
203
|
+
let progressResponse: FileUploadProgressResponse | undefined
|
|
204
|
+
|
|
205
|
+
if (canUseBinary) {
|
|
206
|
+
// Binary protocol: Send header + raw bytes (more efficient)
|
|
207
|
+
const header: BinaryChunkHeader = {
|
|
208
|
+
type: 'FILE_UPLOAD_CHUNK',
|
|
209
|
+
componentId,
|
|
210
|
+
uploadId,
|
|
211
|
+
chunkIndex,
|
|
212
|
+
totalChunks: estimatedTotalChunks,
|
|
213
|
+
requestId
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const binaryMessage = createBinaryChunkMessage(header, chunkBytes)
|
|
217
|
+
progressResponse = await sendBinaryAndWait!(binaryMessage, requestId, 10000) as FileUploadProgressResponse
|
|
218
|
+
} else {
|
|
219
|
+
// JSON protocol: Convert to base64 (legacy/fallback)
|
|
220
|
+
let binary = ''
|
|
221
|
+
for (let j = 0; j < chunkBytes.length; j++) {
|
|
222
|
+
binary += String.fromCharCode(chunkBytes[j])
|
|
223
|
+
}
|
|
224
|
+
const base64Chunk = btoa(binary)
|
|
225
|
+
|
|
226
|
+
const chunkMessage: FileUploadChunkMessage = {
|
|
227
|
+
type: 'FILE_UPLOAD_CHUNK',
|
|
228
|
+
componentId,
|
|
229
|
+
uploadId,
|
|
230
|
+
chunkIndex,
|
|
231
|
+
totalChunks: estimatedTotalChunks,
|
|
232
|
+
data: base64Chunk,
|
|
233
|
+
requestId
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
progressResponse = await sendMessageAndWait!(chunkMessage, 10000) as FileUploadProgressResponse
|
|
237
|
+
}
|
|
188
238
|
|
|
189
239
|
if (progressResponse) {
|
|
190
240
|
const { progress, bytesUploaded } = progressResponse
|
|
@@ -306,4 +356,4 @@ export function useChunkedUpload(componentId: string, options: ChunkedUploadOpti
|
|
|
306
356
|
cancelUpload,
|
|
307
357
|
reset
|
|
308
358
|
}
|
|
309
|
-
}
|
|
359
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { useMemo } from 'react'
|
|
2
|
+
import { useLiveComponents } from '../LiveComponentsProvider'
|
|
3
|
+
import { useChunkedUpload } from './useChunkedUpload'
|
|
4
|
+
import type { ChunkedUploadOptions } from './useChunkedUpload'
|
|
5
|
+
import type { FileUploadCompleteResponse } from '@core/types/types'
|
|
6
|
+
|
|
7
|
+
type LiveUploadActions = {
|
|
8
|
+
$componentId: string | null
|
|
9
|
+
startUpload: (payload: { fileName: string; fileSize: number; fileType: string }) => Promise<any>
|
|
10
|
+
updateProgress: (payload: { progress: number; bytesUploaded: number; totalBytes: number }) => Promise<any>
|
|
11
|
+
completeUpload: (payload: { fileUrl: string }) => Promise<any>
|
|
12
|
+
failUpload: (payload: { error: string }) => Promise<any>
|
|
13
|
+
reset: () => Promise<any>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface LiveChunkedUploadOptions extends Omit<ChunkedUploadOptions, 'sendMessageAndWait' | 'onProgress' | 'onComplete' | 'onError'> {
|
|
17
|
+
onProgress?: (progress: number, bytesUploaded: number, totalBytes: number) => void
|
|
18
|
+
onComplete?: (response: FileUploadCompleteResponse) => void
|
|
19
|
+
onError?: (error: string) => void
|
|
20
|
+
fileUrlResolver?: (fileUrl: string) => string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function useLiveChunkedUpload(live: LiveUploadActions, options: LiveChunkedUploadOptions = {}) {
|
|
24
|
+
const { sendMessageAndWait, sendBinaryAndWait } = useLiveComponents()
|
|
25
|
+
|
|
26
|
+
const {
|
|
27
|
+
onProgress,
|
|
28
|
+
onComplete,
|
|
29
|
+
onError,
|
|
30
|
+
fileUrlResolver,
|
|
31
|
+
...chunkedOptions
|
|
32
|
+
} = options
|
|
33
|
+
|
|
34
|
+
const componentId = live.$componentId ?? ''
|
|
35
|
+
|
|
36
|
+
const base = useChunkedUpload(componentId, {
|
|
37
|
+
...chunkedOptions,
|
|
38
|
+
sendMessageAndWait,
|
|
39
|
+
sendBinaryAndWait, // Enable binary protocol for efficient uploads
|
|
40
|
+
onProgress: (pct, uploaded, total) => {
|
|
41
|
+
void live.updateProgress({ progress: pct, bytesUploaded: uploaded, totalBytes: total }).catch(() => {})
|
|
42
|
+
onProgress?.(pct, uploaded, total)
|
|
43
|
+
},
|
|
44
|
+
onComplete: (response) => {
|
|
45
|
+
const rawUrl = response.fileUrl || ''
|
|
46
|
+
const resolvedUrl = fileUrlResolver ? fileUrlResolver(rawUrl) : rawUrl
|
|
47
|
+
void live.completeUpload({ fileUrl: resolvedUrl }).catch(() => {})
|
|
48
|
+
onComplete?.(response)
|
|
49
|
+
},
|
|
50
|
+
onError: (error) => {
|
|
51
|
+
void live.failUpload({ error }).catch(() => {})
|
|
52
|
+
onError?.(error)
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
const uploadFile = useMemo(() => {
|
|
57
|
+
return async (file: File) => {
|
|
58
|
+
if (!live.$componentId) {
|
|
59
|
+
const msg = 'WebSocket not ready. Wait a moment and try again.'
|
|
60
|
+
void live.failUpload({ error: msg }).catch(() => {})
|
|
61
|
+
onError?.(msg)
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
await live.startUpload({
|
|
66
|
+
fileName: file.name,
|
|
67
|
+
fileSize: file.size,
|
|
68
|
+
fileType: file.type || 'application/octet-stream'
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
await base.uploadFile(file)
|
|
72
|
+
}
|
|
73
|
+
}, [base, live, onError])
|
|
74
|
+
|
|
75
|
+
const reset = useMemo(() => {
|
|
76
|
+
return async () => {
|
|
77
|
+
await live.reset()
|
|
78
|
+
base.reset()
|
|
79
|
+
}
|
|
80
|
+
}, [base, live])
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
...base,
|
|
84
|
+
uploadFile,
|
|
85
|
+
reset
|
|
86
|
+
}
|
|
87
|
+
}
|