create-fluxstack 1.13.0 → 1.15.0
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/LLMD/patterns/anti-patterns.md +100 -0
- package/LLMD/reference/routing.md +39 -39
- package/LLMD/resources/live-auth.md +20 -2
- package/LLMD/resources/live-components.md +300 -21
- package/LLMD/resources/live-logging.md +95 -33
- package/LLMD/resources/live-upload.md +59 -8
- package/app/client/.live-stubs/LiveAdminPanel.js +5 -0
- package/app/client/.live-stubs/LiveChat.js +7 -0
- package/app/client/.live-stubs/LiveCounter.js +9 -0
- package/app/client/.live-stubs/LiveForm.js +11 -0
- package/app/client/.live-stubs/LiveLocalCounter.js +8 -0
- package/app/client/.live-stubs/LiveRoomChat.js +10 -0
- package/app/client/.live-stubs/LiveTodoList.js +9 -0
- package/app/client/.live-stubs/LiveUpload.js +15 -0
- package/app/client/index.html +2 -2
- package/app/client/public/favicon.svg +46 -0
- package/app/client/src/App.tsx +13 -1
- package/app/client/src/assets/fluxstack-static.svg +46 -0
- package/app/client/src/assets/fluxstack.svg +183 -0
- package/app/client/src/components/AppLayout.tsx +146 -9
- package/app/client/src/components/BackButton.tsx +13 -13
- package/app/client/src/components/DemoPage.tsx +4 -4
- package/app/client/src/live/AuthDemo.tsx +23 -21
- package/app/client/src/live/ChatDemo.tsx +2 -2
- package/app/client/src/live/CounterDemo.tsx +12 -12
- package/app/client/src/live/FormDemo.tsx +2 -2
- package/app/client/src/live/LiveDebuggerPanel.tsx +779 -0
- package/app/client/src/live/RoomChatDemo.tsx +24 -16
- package/app/client/src/live/TodoListDemo.tsx +158 -0
- package/app/client/src/main.tsx +13 -13
- package/app/client/src/pages/ApiTestPage.tsx +6 -6
- package/app/client/src/pages/HomePage.tsx +80 -52
- package/app/server/auth/DevAuthProvider.ts +2 -2
- package/app/server/auth/JWTAuthProvider.example.ts +2 -2
- package/app/server/index.ts +2 -2
- package/app/server/live/LiveAdminPanel.ts +2 -1
- package/app/server/live/LiveChat.ts +78 -77
- package/app/server/live/LiveCounter.ts +1 -1
- package/app/server/live/LiveForm.ts +1 -0
- package/app/server/live/LiveLocalCounter.ts +38 -37
- package/app/server/live/LiveProtectedChat.ts +2 -1
- package/app/server/live/LiveRoomChat.ts +1 -0
- package/app/server/live/LiveTodoList.ts +110 -0
- package/app/server/live/LiveUpload.ts +1 -0
- package/app/server/live/register-components.ts +19 -19
- package/app/server/routes/room.routes.ts +1 -2
- package/config/system/runtime.config.ts +4 -0
- package/core/build/live-components-generator.ts +1 -1
- package/core/build/optimizer.ts +235 -235
- package/core/build/vite-plugins.ts +28 -0
- package/core/client/components/LiveDebugger.tsx +1324 -0
- package/core/client/hooks/useLiveUpload.ts +3 -4
- package/core/client/index.ts +41 -21
- package/core/framework/server.ts +1 -1
- package/core/plugins/built-in/index.ts +134 -134
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +4 -0
- package/core/plugins/built-in/vite/index.ts +75 -21
- package/core/server/index.ts +14 -15
- package/core/server/live/auto-generated-components.ts +6 -3
- package/core/server/live/index.ts +95 -21
- package/core/server/live/websocket-plugin.ts +27 -862
- package/core/server/plugins/static-files-plugin.ts +179 -69
- package/core/types/build.ts +219 -219
- package/core/types/plugin.ts +107 -107
- package/core/types/types.ts +77 -890
- package/core/utils/logger/startup-banner.ts +82 -82
- package/core/utils/version.ts +6 -6
- package/create-fluxstack.ts +1 -1
- package/package.json +5 -1
- package/plugins/crypto-auth/index.ts +1 -1
- package/plugins/crypto-auth/server/CryptoAuthLiveProvider.ts +2 -2
- package/vite.config.ts +40 -12
- package/app/client/src/assets/react.svg +0 -1
- package/core/client/LiveComponentsProvider.tsx +0 -531
- package/core/client/components/Live.tsx +0 -105
- package/core/client/hooks/AdaptiveChunkSizer.ts +0 -215
- package/core/client/hooks/state-validator.ts +0 -130
- package/core/client/hooks/useChunkedUpload.ts +0 -359
- package/core/client/hooks/useLiveChunkedUpload.ts +0 -87
- package/core/client/hooks/useLiveComponent.ts +0 -843
- package/core/client/hooks/useRoom.ts +0 -409
- package/core/client/hooks/useRoomProxy.ts +0 -382
- package/core/server/live/ComponentRegistry.ts +0 -1099
- package/core/server/live/FileUploadManager.ts +0 -282
- package/core/server/live/LiveComponentPerformanceMonitor.ts +0 -931
- package/core/server/live/LiveLogger.ts +0 -111
- package/core/server/live/LiveRoomManager.ts +0 -262
- package/core/server/live/RoomEventBus.ts +0 -234
- package/core/server/live/RoomStateManager.ts +0 -172
- package/core/server/live/SingleConnectionManager.ts +0 -0
- package/core/server/live/StateSignature.ts +0 -645
- package/core/server/live/WebSocketConnectionManager.ts +0 -709
- package/core/server/live/auth/LiveAuthContext.ts +0 -71
- package/core/server/live/auth/LiveAuthManager.ts +0 -304
- package/core/server/live/auth/index.ts +0 -19
- package/core/server/live/auth/types.ts +0 -179
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { useMemo } from 'react'
|
|
2
|
-
import { Live } from '
|
|
3
|
-
import {
|
|
4
|
-
import type {
|
|
5
|
-
import type { FileUploadCompleteResponse } from '@core/types/types'
|
|
2
|
+
import { Live, useLiveChunkedUpload } from '@fluxstack/live-react'
|
|
3
|
+
import type { LiveChunkedUploadOptions } from '@fluxstack/live-react'
|
|
4
|
+
import type { FileUploadCompleteResponse } from '@fluxstack/live'
|
|
6
5
|
import { LiveUpload } from '@server/live/LiveUpload'
|
|
7
6
|
|
|
8
7
|
export interface UseLiveUploadOptions {
|
package/core/client/index.ts
CHANGED
|
@@ -1,6 +1,40 @@
|
|
|
1
|
-
//
|
|
1
|
+
// FluxStack Client Core - Main Export
|
|
2
|
+
// Re-exports from @fluxstack/live-react + FluxStack-specific code
|
|
2
3
|
|
|
3
|
-
//
|
|
4
|
+
// === Re-exports from @fluxstack/live-react ===
|
|
5
|
+
|
|
6
|
+
// Provider
|
|
7
|
+
export { LiveComponentsProvider, useLiveComponents } from '@fluxstack/live-react'
|
|
8
|
+
export type {
|
|
9
|
+
LiveComponentsProviderProps,
|
|
10
|
+
LiveComponentsContextValue,
|
|
11
|
+
} from '@fluxstack/live-react'
|
|
12
|
+
export type { LiveAuthOptions } from '@fluxstack/live-react'
|
|
13
|
+
|
|
14
|
+
// Live.use() API
|
|
15
|
+
export { Live } from '@fluxstack/live-react'
|
|
16
|
+
|
|
17
|
+
// Upload Hooks
|
|
18
|
+
export { useChunkedUpload } from '@fluxstack/live-react'
|
|
19
|
+
export type { ChunkedUploadOptions, ChunkedUploadState } from '@fluxstack/live-react'
|
|
20
|
+
export { useLiveChunkedUpload } from '@fluxstack/live-react'
|
|
21
|
+
export type { LiveChunkedUploadOptions } from '@fluxstack/live-react'
|
|
22
|
+
|
|
23
|
+
// Debugger Hook
|
|
24
|
+
export { useLiveDebugger } from '@fluxstack/live-react'
|
|
25
|
+
export type {
|
|
26
|
+
DebugEvent,
|
|
27
|
+
DebugEventType,
|
|
28
|
+
ComponentSnapshot,
|
|
29
|
+
DebugSnapshot,
|
|
30
|
+
DebugFilter,
|
|
31
|
+
UseLiveDebuggerReturn,
|
|
32
|
+
UseLiveDebuggerOptions,
|
|
33
|
+
} from '@fluxstack/live-react'
|
|
34
|
+
|
|
35
|
+
// === FluxStack-specific (stays here) ===
|
|
36
|
+
|
|
37
|
+
// Eden Treaty API client
|
|
4
38
|
export {
|
|
5
39
|
createEdenClient,
|
|
6
40
|
getErrorMessage,
|
|
@@ -9,23 +43,9 @@ export {
|
|
|
9
43
|
type EdenClientOptions
|
|
10
44
|
} from './api'
|
|
11
45
|
|
|
12
|
-
//
|
|
13
|
-
export {
|
|
14
|
-
|
|
15
|
-
useLiveComponents
|
|
16
|
-
} from './LiveComponentsProvider'
|
|
17
|
-
export type {
|
|
18
|
-
LiveComponentsProviderProps,
|
|
19
|
-
LiveComponentsContextValue,
|
|
20
|
-
LiveAuthOptions
|
|
21
|
-
} from './LiveComponentsProvider'
|
|
22
|
-
|
|
23
|
-
// Chunked Upload Hook
|
|
24
|
-
export { useChunkedUpload } from './hooks/useChunkedUpload'
|
|
25
|
-
export type { ChunkedUploadOptions, ChunkedUploadState } from './hooks/useChunkedUpload'
|
|
26
|
-
export { useLiveChunkedUpload } from './hooks/useLiveChunkedUpload'
|
|
27
|
-
export type { LiveChunkedUploadOptions } from './hooks/useLiveChunkedUpload'
|
|
28
|
-
export { useLiveUpload } from './hooks/useLiveUpload'
|
|
46
|
+
// LiveDebugger UI component (React component, 1325 lines - not extracted to lib)
|
|
47
|
+
export { LiveDebugger } from './components/LiveDebugger'
|
|
48
|
+
export type { LiveDebuggerProps } from './components/LiveDebugger'
|
|
29
49
|
|
|
30
|
-
//
|
|
31
|
-
export {
|
|
50
|
+
// useLiveUpload (FluxStack-specific convenience wrapper)
|
|
51
|
+
export { useLiveUpload } from './hooks/useLiveUpload'
|
package/core/framework/server.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { fluxStackConfig } from "@config"
|
|
|
7
7
|
import { getEnvironmentInfo } from "@core/config"
|
|
8
8
|
import { logger } from "@core/utils/logger"
|
|
9
9
|
import { displayStartupBanner, type StartupInfo } from "@core/utils/logger/startup-banner"
|
|
10
|
-
import { componentRegistry } from "@core/server/live
|
|
10
|
+
import { componentRegistry } from "@core/server/live"
|
|
11
11
|
import { FluxStackError } from "@core/utils/errors"
|
|
12
12
|
import { createTimer, formatBytes, isProduction, isDevelopment } from "@core/utils/helpers"
|
|
13
13
|
import type { Plugin } from "@core/plugins"
|
|
@@ -1,135 +1,135 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Built-in Plugins for FluxStack
|
|
3
|
-
* Core plugins that provide essential functionality
|
|
4
|
-
*
|
|
5
|
-
* Note: Logger is NOT a plugin - it's core infrastructure used by plugins
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// Import all built-in plugins
|
|
9
|
-
import { swaggerPlugin } from './swagger'
|
|
10
|
-
import { vitePlugin } from './vite'
|
|
11
|
-
import { monitoringPlugin } from './monitoring'
|
|
12
|
-
|
|
13
|
-
// Export individual plugins
|
|
14
|
-
export { swaggerPlugin } from './swagger'
|
|
15
|
-
export { vitePlugin } from './vite'
|
|
16
|
-
export { monitoringPlugin } from './monitoring'
|
|
17
|
-
|
|
18
|
-
// Deprecated: staticPlugin is now merged into vitePlugin (auto-detects dev/prod)
|
|
19
|
-
/** @deprecated Use vitePlugin instead - it now handles both dev and prod */
|
|
20
|
-
export const staticPlugin = vitePlugin
|
|
21
|
-
|
|
22
|
-
// Export as a collection
|
|
23
|
-
export const builtInPlugins = {
|
|
24
|
-
swagger: swaggerPlugin,
|
|
25
|
-
vite: vitePlugin,
|
|
26
|
-
static: staticPlugin,
|
|
27
|
-
monitoring: monitoringPlugin
|
|
28
|
-
} as const
|
|
29
|
-
|
|
30
|
-
// Export as an array for easy registration
|
|
31
|
-
export const builtInPluginsList = [
|
|
32
|
-
swaggerPlugin,
|
|
33
|
-
vitePlugin,
|
|
34
|
-
staticPlugin,
|
|
35
|
-
monitoringPlugin
|
|
36
|
-
] as const
|
|
37
|
-
|
|
38
|
-
// Plugin categories
|
|
39
|
-
export const pluginCategories = {
|
|
40
|
-
core: [vitePlugin], // vitePlugin now handles both dev (Vite) and prod (static)
|
|
41
|
-
development: [vitePlugin],
|
|
42
|
-
documentation: [swaggerPlugin],
|
|
43
|
-
monitoring: [monitoringPlugin]
|
|
44
|
-
} as const
|
|
45
|
-
|
|
46
|
-
// Default plugin configuration
|
|
47
|
-
export const defaultPluginConfig = {
|
|
48
|
-
swagger: {
|
|
49
|
-
enabled: true,
|
|
50
|
-
path: '/swagger',
|
|
51
|
-
title: 'FluxStack API',
|
|
52
|
-
description: 'Modern full-stack TypeScript framework with type-safe API endpoints'
|
|
53
|
-
},
|
|
54
|
-
vite: {
|
|
55
|
-
enabled: true,
|
|
56
|
-
port: 5173,
|
|
57
|
-
host: 'localhost',
|
|
58
|
-
checkInterval: 2000,
|
|
59
|
-
maxRetries: 10,
|
|
60
|
-
timeout: 5000
|
|
61
|
-
},
|
|
62
|
-
static: {
|
|
63
|
-
enabled: true,
|
|
64
|
-
publicDir: 'public',
|
|
65
|
-
distDir: 'dist/client',
|
|
66
|
-
indexFile: 'index.html',
|
|
67
|
-
spa: {
|
|
68
|
-
enabled: true,
|
|
69
|
-
fallback: 'index.html'
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
monitoring: {
|
|
73
|
-
enabled: false, // Disabled by default to avoid overhead
|
|
74
|
-
httpMetrics: true,
|
|
75
|
-
systemMetrics: true,
|
|
76
|
-
customMetrics: true,
|
|
77
|
-
collectInterval: 5000,
|
|
78
|
-
retentionPeriod: 300000,
|
|
79
|
-
exporters: [
|
|
80
|
-
{
|
|
81
|
-
type: 'console',
|
|
82
|
-
interval: 30000,
|
|
83
|
-
enabled: false
|
|
84
|
-
}
|
|
85
|
-
],
|
|
86
|
-
thresholds: {
|
|
87
|
-
responseTime: 1000,
|
|
88
|
-
errorRate: 0.05,
|
|
89
|
-
memoryUsage: 0.8,
|
|
90
|
-
cpuUsage: 0.8
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
} as const
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Get default plugins for a specific environment
|
|
97
|
-
*/
|
|
98
|
-
export function getDefaultPlugins(environment: 'development' | 'production' | 'test' = 'development') {
|
|
99
|
-
// vitePlugin now auto-detects dev/prod and serves appropriately
|
|
100
|
-
const basePlugins = [vitePlugin]
|
|
101
|
-
|
|
102
|
-
switch (environment) {
|
|
103
|
-
case 'development':
|
|
104
|
-
return [...basePlugins, swaggerPlugin, monitoringPlugin]
|
|
105
|
-
case 'production':
|
|
106
|
-
return [...basePlugins, monitoringPlugin]
|
|
107
|
-
case 'test':
|
|
108
|
-
return [] // Minimal plugins for testing
|
|
109
|
-
default:
|
|
110
|
-
return basePlugins
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Get plugin by name
|
|
116
|
-
*/
|
|
117
|
-
export function getBuiltInPlugin(name: string) {
|
|
118
|
-
return builtInPlugins[name as keyof typeof builtInPlugins]
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Check if a plugin is built-in
|
|
123
|
-
*/
|
|
124
|
-
export function isBuiltInPlugin(name: string): boolean {
|
|
125
|
-
return name in builtInPlugins
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Get plugins by category
|
|
130
|
-
*/
|
|
131
|
-
export function getPluginsByCategory(category: keyof typeof pluginCategories) {
|
|
132
|
-
return pluginCategories[category] || []
|
|
133
|
-
}
|
|
134
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Built-in Plugins for FluxStack
|
|
3
|
+
* Core plugins that provide essential functionality
|
|
4
|
+
*
|
|
5
|
+
* Note: Logger is NOT a plugin - it's core infrastructure used by plugins
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Import all built-in plugins
|
|
9
|
+
import { swaggerPlugin } from './swagger'
|
|
10
|
+
import { vitePlugin } from './vite'
|
|
11
|
+
import { monitoringPlugin } from './monitoring'
|
|
12
|
+
|
|
13
|
+
// Export individual plugins
|
|
14
|
+
export { swaggerPlugin } from './swagger'
|
|
15
|
+
export { vitePlugin } from './vite'
|
|
16
|
+
export { monitoringPlugin } from './monitoring'
|
|
17
|
+
|
|
18
|
+
// Deprecated: staticPlugin is now merged into vitePlugin (auto-detects dev/prod)
|
|
19
|
+
/** @deprecated Use vitePlugin instead - it now handles both dev and prod */
|
|
20
|
+
export const staticPlugin = vitePlugin
|
|
21
|
+
|
|
22
|
+
// Export as a collection
|
|
23
|
+
export const builtInPlugins = {
|
|
24
|
+
swagger: swaggerPlugin,
|
|
25
|
+
vite: vitePlugin,
|
|
26
|
+
static: staticPlugin,
|
|
27
|
+
monitoring: monitoringPlugin
|
|
28
|
+
} as const
|
|
29
|
+
|
|
30
|
+
// Export as an array for easy registration
|
|
31
|
+
export const builtInPluginsList = [
|
|
32
|
+
swaggerPlugin,
|
|
33
|
+
vitePlugin,
|
|
34
|
+
staticPlugin,
|
|
35
|
+
monitoringPlugin
|
|
36
|
+
] as const
|
|
37
|
+
|
|
38
|
+
// Plugin categories
|
|
39
|
+
export const pluginCategories = {
|
|
40
|
+
core: [vitePlugin], // vitePlugin now handles both dev (Vite) and prod (static)
|
|
41
|
+
development: [vitePlugin],
|
|
42
|
+
documentation: [swaggerPlugin],
|
|
43
|
+
monitoring: [monitoringPlugin]
|
|
44
|
+
} as const
|
|
45
|
+
|
|
46
|
+
// Default plugin configuration
|
|
47
|
+
export const defaultPluginConfig = {
|
|
48
|
+
swagger: {
|
|
49
|
+
enabled: true,
|
|
50
|
+
path: '/swagger',
|
|
51
|
+
title: 'FluxStack API',
|
|
52
|
+
description: 'Modern full-stack TypeScript framework with type-safe API endpoints'
|
|
53
|
+
},
|
|
54
|
+
vite: {
|
|
55
|
+
enabled: true,
|
|
56
|
+
port: 5173,
|
|
57
|
+
host: 'localhost',
|
|
58
|
+
checkInterval: 2000,
|
|
59
|
+
maxRetries: 10,
|
|
60
|
+
timeout: 5000
|
|
61
|
+
},
|
|
62
|
+
static: {
|
|
63
|
+
enabled: true,
|
|
64
|
+
publicDir: 'public',
|
|
65
|
+
distDir: 'dist/client',
|
|
66
|
+
indexFile: 'index.html',
|
|
67
|
+
spa: {
|
|
68
|
+
enabled: true,
|
|
69
|
+
fallback: 'index.html'
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
monitoring: {
|
|
73
|
+
enabled: false, // Disabled by default to avoid overhead
|
|
74
|
+
httpMetrics: true,
|
|
75
|
+
systemMetrics: true,
|
|
76
|
+
customMetrics: true,
|
|
77
|
+
collectInterval: 5000,
|
|
78
|
+
retentionPeriod: 300000,
|
|
79
|
+
exporters: [
|
|
80
|
+
{
|
|
81
|
+
type: 'console',
|
|
82
|
+
interval: 30000,
|
|
83
|
+
enabled: false
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
thresholds: {
|
|
87
|
+
responseTime: 1000,
|
|
88
|
+
errorRate: 0.05,
|
|
89
|
+
memoryUsage: 0.8,
|
|
90
|
+
cpuUsage: 0.8
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
} as const
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get default plugins for a specific environment
|
|
97
|
+
*/
|
|
98
|
+
export function getDefaultPlugins(environment: 'development' | 'production' | 'test' = 'development') {
|
|
99
|
+
// vitePlugin now auto-detects dev/prod and serves appropriately
|
|
100
|
+
const basePlugins = [vitePlugin]
|
|
101
|
+
|
|
102
|
+
switch (environment) {
|
|
103
|
+
case 'development':
|
|
104
|
+
return [...basePlugins, swaggerPlugin, monitoringPlugin]
|
|
105
|
+
case 'production':
|
|
106
|
+
return [...basePlugins, monitoringPlugin]
|
|
107
|
+
case 'test':
|
|
108
|
+
return [] // Minimal plugins for testing
|
|
109
|
+
default:
|
|
110
|
+
return basePlugins
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get plugin by name
|
|
116
|
+
*/
|
|
117
|
+
export function getBuiltInPlugin(name: string) {
|
|
118
|
+
return builtInPlugins[name as keyof typeof builtInPlugins]
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Check if a plugin is built-in
|
|
123
|
+
*/
|
|
124
|
+
export function isBuiltInPlugin(name: string): boolean {
|
|
125
|
+
return name in builtInPlugins
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Get plugins by category
|
|
130
|
+
*/
|
|
131
|
+
export function getPluginsByCategory(category: keyof typeof pluginCategories) {
|
|
132
|
+
return pluginCategories[category] || []
|
|
133
|
+
}
|
|
134
|
+
|
|
135
135
|
export default builtInPlugins
|
|
@@ -27,6 +27,7 @@ ${clientLink}
|
|
|
27
27
|
|
|
28
28
|
export class ${name} extends LiveComponent<typeof ${name}.defaultState> {
|
|
29
29
|
static componentName = '${name}'
|
|
30
|
+
static publicActions = ['increment', 'decrement', 'reset'] as const
|
|
30
31
|
static defaultState = {
|
|
31
32
|
count: 0
|
|
32
33
|
}
|
|
@@ -58,6 +59,7 @@ ${clientLink}
|
|
|
58
59
|
|
|
59
60
|
export class ${name} extends LiveComponent<typeof ${name}.defaultState> {
|
|
60
61
|
static componentName = '${name}'
|
|
62
|
+
static publicActions = ['submit', 'reset'] as const
|
|
61
63
|
static defaultState = {
|
|
62
64
|
name: '',
|
|
63
65
|
email: '',
|
|
@@ -89,6 +91,7 @@ ${clientLink}
|
|
|
89
91
|
|
|
90
92
|
export class ${name} extends LiveComponent<typeof ${name}.defaultState> {
|
|
91
93
|
static componentName = '${name}'
|
|
94
|
+
static publicActions = ['sendMessage', 'setUsername'] as const
|
|
92
95
|
static defaultState = {
|
|
93
96
|
messages: [] as Array<{ id: string; text: string; username: string; timestamp: string }>,
|
|
94
97
|
username: '',
|
|
@@ -125,6 +128,7 @@ ${clientLink}
|
|
|
125
128
|
|
|
126
129
|
export class ${name} extends LiveComponent<typeof ${name}.defaultState> {
|
|
127
130
|
static componentName = '${name}'
|
|
131
|
+
static publicActions = ['updateMessage', 'increment', 'reset'] as const
|
|
128
132
|
static defaultState = {
|
|
129
133
|
message: 'Hello from ${name}!',
|
|
130
134
|
count: 0
|
|
@@ -4,7 +4,7 @@ import { clientConfig } from '@config'
|
|
|
4
4
|
import { pluginsConfig } from '@config'
|
|
5
5
|
import { isDevelopment } from "@core/utils/helpers"
|
|
6
6
|
import { join } from "path"
|
|
7
|
-
import {
|
|
7
|
+
import { existsSync } from "fs"
|
|
8
8
|
|
|
9
9
|
type Plugin = FluxStack.Plugin
|
|
10
10
|
|
|
@@ -21,24 +21,30 @@ const STATIC_MAX_AGE = 31536000
|
|
|
21
21
|
const HASHED_EXT = /\.[0-9a-f]{8,}\.\w+$/
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
24
|
+
* Collect all files under `dir` using Bun.Glob (native C++ implementation).
|
|
25
|
+
* Returns a map of relative URL paths → absolute filesystem paths.
|
|
26
|
+
*
|
|
27
|
+
* Throws if the directory does not exist so callers get a clear signal
|
|
28
|
+
* instead of silently serving nothing.
|
|
26
29
|
*/
|
|
27
|
-
function collectFiles(dir: string
|
|
30
|
+
function collectFiles(dir: string): Map<string, string> {
|
|
31
|
+
if (!existsSync(dir)) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
`Static file directory "${dir}" does not exist. ` +
|
|
34
|
+
`Run the client build first or check your configuration.`
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
28
38
|
const map = new Map<string, string>()
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
map.set(rel, join(dir, entry.name))
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
} catch {}
|
|
39
|
+
const glob = new Bun.Glob("**/*")
|
|
40
|
+
|
|
41
|
+
for (const relativePath of glob.scanSync({ cwd: dir, onlyFiles: true, dot: true })) {
|
|
42
|
+
// scanSync may return OS-native separators (backslashes on Windows)
|
|
43
|
+
// Normalize to forward slashes so URL lookups always match
|
|
44
|
+
const urlPath = '/' + relativePath.replaceAll('\\', '/')
|
|
45
|
+
map.set(urlPath, join(dir, relativePath))
|
|
46
|
+
}
|
|
47
|
+
|
|
42
48
|
return map
|
|
43
49
|
}
|
|
44
50
|
|
|
@@ -60,6 +66,15 @@ function createStaticFallback() {
|
|
|
60
66
|
// Bun.file() handle cache — avoids re-creating handles on repeated requests
|
|
61
67
|
const fileCache = new Map<string, ReturnType<typeof Bun.file>>()
|
|
62
68
|
|
|
69
|
+
// Build a set of paths that have a pre-compressed .gz sibling
|
|
70
|
+
const gzSet = new Set<string>()
|
|
71
|
+
for (const [rel] of fileMap) {
|
|
72
|
+
if (rel.endsWith('.gz')) {
|
|
73
|
+
// "/assets/app.abc123.js.gz" → "/assets/app.abc123.js"
|
|
74
|
+
gzSet.add(rel.slice(0, -3))
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
63
78
|
return (c: { request?: Request }) => {
|
|
64
79
|
const req = c.request
|
|
65
80
|
if (!req) return
|
|
@@ -96,6 +111,39 @@ function createStaticFallback() {
|
|
|
96
111
|
// O(1) lookup in pre-scanned file map
|
|
97
112
|
const absolutePath = fileMap.get(pathname)
|
|
98
113
|
if (absolutePath) {
|
|
114
|
+
// Check for pre-compressed .gz variant
|
|
115
|
+
const acceptEncoding = req.headers.get('accept-encoding') || ''
|
|
116
|
+
if (gzSet.has(pathname) && acceptEncoding.includes('gzip')) {
|
|
117
|
+
const gzPath = pathname + '.gz'
|
|
118
|
+
const gzAbsolute = fileMap.get(gzPath)
|
|
119
|
+
if (gzAbsolute) {
|
|
120
|
+
let gzFile = fileCache.get(gzPath)
|
|
121
|
+
if (!gzFile) {
|
|
122
|
+
gzFile = Bun.file(gzAbsolute)
|
|
123
|
+
fileCache.set(gzPath, gzFile)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Determine original content type from the uncompressed file
|
|
127
|
+
let origFile = fileCache.get(pathname)
|
|
128
|
+
if (!origFile) {
|
|
129
|
+
origFile = Bun.file(absolutePath)
|
|
130
|
+
fileCache.set(pathname, origFile)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const headers: Record<string, string> = {
|
|
134
|
+
'Content-Encoding': 'gzip',
|
|
135
|
+
'Content-Type': origFile.type || 'application/octet-stream',
|
|
136
|
+
'Vary': 'Accept-Encoding',
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (HASHED_EXT.test(pathname)) {
|
|
140
|
+
headers['Cache-Control'] = `public, max-age=${STATIC_MAX_AGE}, immutable`
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return new Response(gzFile, { headers })
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
99
147
|
let file = fileCache.get(pathname)
|
|
100
148
|
if (!file) {
|
|
101
149
|
file = Bun.file(absolutePath)
|
|
@@ -114,14 +162,19 @@ function createStaticFallback() {
|
|
|
114
162
|
return file
|
|
115
163
|
}
|
|
116
164
|
|
|
117
|
-
// SPA fallback: serve index.html for unmatched routes
|
|
165
|
+
// SPA fallback: serve index.html for unmatched routes with no-cache
|
|
166
|
+
// so the browser always checks for a newer version on deploy
|
|
118
167
|
if (indexFile) {
|
|
119
|
-
return indexFile
|
|
168
|
+
return new Response(indexFile, {
|
|
169
|
+
headers: {
|
|
170
|
+
'Cache-Control': 'no-cache',
|
|
171
|
+
}
|
|
172
|
+
})
|
|
120
173
|
}
|
|
121
174
|
}
|
|
122
175
|
}
|
|
123
176
|
|
|
124
|
-
/** Proxy request to Vite dev server */
|
|
177
|
+
/** Proxy request to Vite dev server — streams the response body */
|
|
125
178
|
async function proxyToVite(ctx: RequestContext): Promise<void> {
|
|
126
179
|
const { host, port } = clientConfig.vite
|
|
127
180
|
|
|
@@ -143,7 +196,8 @@ async function proxyToVite(ctx: RequestContext): Promise<void> {
|
|
|
143
196
|
})
|
|
144
197
|
|
|
145
198
|
ctx.handled = true
|
|
146
|
-
|
|
199
|
+
// Stream the response body instead of buffering the entire payload in memory
|
|
200
|
+
ctx.response = new Response(response.body, {
|
|
147
201
|
status: response.status,
|
|
148
202
|
statusText: response.statusText,
|
|
149
203
|
headers: response.headers
|
package/core/server/index.ts
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
// FluxStack framework exports
|
|
2
|
-
export { FluxStackFramework } from "../framework/server"
|
|
3
|
-
export { vitePlugin, staticPlugin } from "../plugins/built-in"
|
|
4
|
-
export { swaggerPlugin } from "../plugins/built-in/swagger"
|
|
5
|
-
export { PluginRegistry } from "../plugins/registry"
|
|
6
|
-
export * from "../types"
|
|
7
|
-
|
|
8
|
-
// Live Components exports
|
|
9
|
-
export { liveComponentsPlugin } from "./live
|
|
10
|
-
export {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
// FluxStack framework exports
|
|
2
|
+
export { FluxStackFramework } from "../framework/server"
|
|
3
|
+
export { vitePlugin, staticPlugin } from "../plugins/built-in"
|
|
4
|
+
export { swaggerPlugin } from "../plugins/built-in/swagger"
|
|
5
|
+
export { PluginRegistry } from "../plugins/registry"
|
|
6
|
+
export * from "../types"
|
|
7
|
+
|
|
8
|
+
// Live Components exports
|
|
9
|
+
export { liveComponentsPlugin, componentRegistry } from "./live"
|
|
10
|
+
export { LiveComponent } from "../types/types"
|
|
11
|
+
|
|
12
|
+
// Static Files Plugin
|
|
13
|
+
export { staticFilesPlugin } from "./plugins/static-files-plugin"
|
|
14
|
+
|
|
16
15
|
export * from "../types/types"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// 🔥 Auto-generated Live Components Registration
|
|
2
2
|
// This file is automatically generated during build time - DO NOT EDIT MANUALLY
|
|
3
|
-
// Generated at: 2026-
|
|
3
|
+
// Generated at: 2026-03-01T19:00:29.650Z
|
|
4
4
|
|
|
5
5
|
import { LiveAdminPanel } from "@app/server/live/LiveAdminPanel"
|
|
6
6
|
import { LiveChat } from "@app/server/live/LiveChat"
|
|
@@ -9,8 +9,9 @@ import { LiveForm } from "@app/server/live/LiveForm"
|
|
|
9
9
|
import { LiveLocalCounter } from "@app/server/live/LiveLocalCounter"
|
|
10
10
|
import { LiveProtectedChat } from "@app/server/live/LiveProtectedChat"
|
|
11
11
|
import { LiveRoomChat } from "@app/server/live/LiveRoomChat"
|
|
12
|
+
import { LiveTodoList } from "@app/server/live/LiveTodoList"
|
|
12
13
|
import { LiveUpload } from "@app/server/live/LiveUpload"
|
|
13
|
-
import { componentRegistry } from "@core/server/live
|
|
14
|
+
import { componentRegistry } from "@core/server/live"
|
|
14
15
|
|
|
15
16
|
// Register all components statically for production bundle
|
|
16
17
|
function registerAllComponents() {
|
|
@@ -23,9 +24,10 @@ function registerAllComponents() {
|
|
|
23
24
|
componentRegistry.registerComponentClass('LiveLocalCounter', LiveLocalCounter)
|
|
24
25
|
componentRegistry.registerComponentClass('LiveProtectedChat', LiveProtectedChat)
|
|
25
26
|
componentRegistry.registerComponentClass('LiveRoomChat', LiveRoomChat)
|
|
27
|
+
componentRegistry.registerComponentClass('LiveTodoList', LiveTodoList)
|
|
26
28
|
componentRegistry.registerComponentClass('LiveUpload', LiveUpload)
|
|
27
29
|
|
|
28
|
-
console.log('📝 Live components registered successfully! (
|
|
30
|
+
console.log('📝 Live components registered successfully! (9 components)')
|
|
29
31
|
} catch (error) {
|
|
30
32
|
console.warn('⚠️ Error registering components:', error)
|
|
31
33
|
}
|
|
@@ -43,5 +45,6 @@ export {
|
|
|
43
45
|
LiveLocalCounter,
|
|
44
46
|
LiveProtectedChat,
|
|
45
47
|
LiveRoomChat,
|
|
48
|
+
LiveTodoList,
|
|
46
49
|
LiveUpload
|
|
47
50
|
}
|