create-fluxstack 1.13.0 → 1.14.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 +94 -10
- package/LLMD/resources/live-logging.md +95 -33
- package/LLMD/resources/live-upload.md +59 -8
- package/app/client/index.html +2 -2
- package/app/client/public/favicon.svg +46 -0
- package/app/client/src/App.tsx +2 -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 +138 -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/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/live/LiveAdminPanel.ts +1 -0
- 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 +1 -0
- package/app/server/live/LiveRoomChat.ts +1 -0
- package/app/server/live/LiveUpload.ts +1 -0
- package/app/server/live/register-components.ts +19 -19
- package/config/system/runtime.config.ts +4 -0
- package/core/build/optimizer.ts +235 -235
- package/core/client/components/Live.tsx +17 -11
- package/core/client/components/LiveDebugger.tsx +1324 -0
- package/core/client/hooks/AdaptiveChunkSizer.ts +215 -215
- package/core/client/hooks/useLiveComponent.ts +11 -1
- package/core/client/hooks/useLiveDebugger.ts +392 -0
- package/core/client/index.ts +14 -0
- 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 +15 -15
- package/core/server/live/ComponentRegistry.ts +55 -26
- package/core/server/live/FileUploadManager.ts +188 -24
- package/core/server/live/LiveDebugger.ts +462 -0
- package/core/server/live/LiveLogger.ts +38 -5
- package/core/server/live/LiveRoomManager.ts +17 -1
- package/core/server/live/StateSignature.ts +87 -27
- package/core/server/live/WebSocketConnectionManager.ts +11 -10
- package/core/server/live/auto-generated-components.ts +1 -1
- package/core/server/live/websocket-plugin.ts +233 -8
- 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 +145 -9
- package/core/utils/logger/startup-banner.ts +82 -82
- package/core/utils/version.ts +6 -6
- package/package.json +1 -1
- package/app/client/src/assets/react.svg +0 -1
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
// 🔍 FluxStack Live Component Debugger - Client Hook
|
|
2
|
+
//
|
|
3
|
+
// Connects to the debug WebSocket endpoint and streams debug events.
|
|
4
|
+
// Provides reactive state for building debugger UIs.
|
|
5
|
+
//
|
|
6
|
+
// Usage:
|
|
7
|
+
// const debugger = useLiveDebugger()
|
|
8
|
+
// debugger.components // Active components with current states
|
|
9
|
+
// debugger.events // Event timeline
|
|
10
|
+
// debugger.connected // Connection status
|
|
11
|
+
|
|
12
|
+
import { useState, useEffect, useRef, useCallback } from 'react'
|
|
13
|
+
|
|
14
|
+
// ===== Types (mirrored from server) =====
|
|
15
|
+
|
|
16
|
+
export type DebugEventType =
|
|
17
|
+
| 'COMPONENT_MOUNT'
|
|
18
|
+
| 'COMPONENT_UNMOUNT'
|
|
19
|
+
| 'COMPONENT_REHYDRATE'
|
|
20
|
+
| 'STATE_CHANGE'
|
|
21
|
+
| 'ACTION_CALL'
|
|
22
|
+
| 'ACTION_RESULT'
|
|
23
|
+
| 'ACTION_ERROR'
|
|
24
|
+
| 'ROOM_JOIN'
|
|
25
|
+
| 'ROOM_LEAVE'
|
|
26
|
+
| 'ROOM_EMIT'
|
|
27
|
+
| 'ROOM_EVENT_RECEIVED'
|
|
28
|
+
| 'WS_CONNECT'
|
|
29
|
+
| 'WS_DISCONNECT'
|
|
30
|
+
| 'ERROR'
|
|
31
|
+
|
|
32
|
+
export interface DebugEvent {
|
|
33
|
+
id: string
|
|
34
|
+
timestamp: number
|
|
35
|
+
type: DebugEventType
|
|
36
|
+
componentId: string | null
|
|
37
|
+
componentName: string | null
|
|
38
|
+
data: Record<string, unknown>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ComponentSnapshot {
|
|
42
|
+
componentId: string
|
|
43
|
+
componentName: string
|
|
44
|
+
/** Developer-defined label for easier identification in the debugger */
|
|
45
|
+
debugLabel?: string
|
|
46
|
+
state: Record<string, unknown>
|
|
47
|
+
rooms: string[]
|
|
48
|
+
mountedAt: number
|
|
49
|
+
lastActivity: number
|
|
50
|
+
actionCount: number
|
|
51
|
+
stateChangeCount: number
|
|
52
|
+
errorCount: number
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface DebugSnapshot {
|
|
56
|
+
components: ComponentSnapshot[]
|
|
57
|
+
connections: number
|
|
58
|
+
uptime: number
|
|
59
|
+
totalEvents: number
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface DebugFilter {
|
|
63
|
+
componentId?: string | null
|
|
64
|
+
types?: Set<DebugEventType>
|
|
65
|
+
search?: string
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface UseLiveDebuggerReturn {
|
|
69
|
+
// Connection
|
|
70
|
+
connected: boolean
|
|
71
|
+
connecting: boolean
|
|
72
|
+
/** Server reported that debugging is disabled */
|
|
73
|
+
serverDisabled: boolean
|
|
74
|
+
|
|
75
|
+
// Data
|
|
76
|
+
components: ComponentSnapshot[]
|
|
77
|
+
events: DebugEvent[]
|
|
78
|
+
filteredEvents: DebugEvent[]
|
|
79
|
+
snapshot: DebugSnapshot | null
|
|
80
|
+
|
|
81
|
+
// Selected component
|
|
82
|
+
selectedComponentId: string | null
|
|
83
|
+
selectedComponent: ComponentSnapshot | null
|
|
84
|
+
selectComponent: (id: string | null) => void
|
|
85
|
+
|
|
86
|
+
// Filtering
|
|
87
|
+
filter: DebugFilter
|
|
88
|
+
setFilter: (filter: Partial<DebugFilter>) => void
|
|
89
|
+
|
|
90
|
+
// Controls
|
|
91
|
+
paused: boolean
|
|
92
|
+
togglePause: () => void
|
|
93
|
+
clearEvents: () => void
|
|
94
|
+
reconnect: () => void
|
|
95
|
+
|
|
96
|
+
// Stats
|
|
97
|
+
eventCount: number
|
|
98
|
+
componentCount: number
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface UseLiveDebuggerOptions {
|
|
102
|
+
/** Max events to keep in memory. Default: 500 */
|
|
103
|
+
maxEvents?: number
|
|
104
|
+
/** Auto-connect on mount. Default: true */
|
|
105
|
+
autoConnect?: boolean
|
|
106
|
+
/** Custom WebSocket URL */
|
|
107
|
+
url?: string
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ===== Hook =====
|
|
111
|
+
|
|
112
|
+
export function useLiveDebugger(options: UseLiveDebuggerOptions = {}): UseLiveDebuggerReturn {
|
|
113
|
+
const {
|
|
114
|
+
maxEvents = 500,
|
|
115
|
+
autoConnect = true,
|
|
116
|
+
url
|
|
117
|
+
} = options
|
|
118
|
+
|
|
119
|
+
// State
|
|
120
|
+
const [connected, setConnected] = useState(false)
|
|
121
|
+
const [connecting, setConnecting] = useState(false)
|
|
122
|
+
const [components, setComponents] = useState<ComponentSnapshot[]>([])
|
|
123
|
+
const [events, setEvents] = useState<DebugEvent[]>([])
|
|
124
|
+
const [snapshot, setSnapshot] = useState<DebugSnapshot | null>(null)
|
|
125
|
+
const [selectedComponentId, setSelectedComponentId] = useState<string | null>(null)
|
|
126
|
+
const [filter, setFilterState] = useState<DebugFilter>({})
|
|
127
|
+
const [paused, setPaused] = useState(false)
|
|
128
|
+
const [serverDisabled, setServerDisabled] = useState(false)
|
|
129
|
+
|
|
130
|
+
// Refs
|
|
131
|
+
const wsRef = useRef<WebSocket | null>(null)
|
|
132
|
+
const pausedRef = useRef(false)
|
|
133
|
+
const serverDisabledRef = useRef(false)
|
|
134
|
+
const reconnectTimeoutRef = useRef<number | null>(null)
|
|
135
|
+
|
|
136
|
+
// Keep refs in sync
|
|
137
|
+
pausedRef.current = paused
|
|
138
|
+
serverDisabledRef.current = serverDisabled
|
|
139
|
+
|
|
140
|
+
// Build WebSocket URL
|
|
141
|
+
const getWsUrl = useCallback(() => {
|
|
142
|
+
if (url) return url
|
|
143
|
+
if (typeof window === 'undefined') return 'ws://localhost:3000/api/live/debug/ws'
|
|
144
|
+
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
|
|
145
|
+
return `${protocol}//${window.location.host}/api/live/debug/ws`
|
|
146
|
+
}, [url])
|
|
147
|
+
|
|
148
|
+
// Connect
|
|
149
|
+
const connect = useCallback(() => {
|
|
150
|
+
if (wsRef.current?.readyState === WebSocket.CONNECTING) return
|
|
151
|
+
if (wsRef.current?.readyState === WebSocket.OPEN) return
|
|
152
|
+
|
|
153
|
+
setConnecting(true)
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
const ws = new WebSocket(getWsUrl())
|
|
157
|
+
wsRef.current = ws
|
|
158
|
+
|
|
159
|
+
ws.onopen = () => {
|
|
160
|
+
setConnected(true)
|
|
161
|
+
setConnecting(false)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
ws.onmessage = (event) => {
|
|
165
|
+
try {
|
|
166
|
+
const msg = JSON.parse(event.data)
|
|
167
|
+
|
|
168
|
+
if (msg.type === 'DEBUG_DISABLED') {
|
|
169
|
+
// Server has debugging disabled — stop reconnecting
|
|
170
|
+
setServerDisabled(true)
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (msg.type === 'DEBUG_WELCOME') {
|
|
175
|
+
// Initial snapshot
|
|
176
|
+
setServerDisabled(false)
|
|
177
|
+
const snap = msg.snapshot as DebugSnapshot
|
|
178
|
+
setSnapshot(snap)
|
|
179
|
+
setComponents(snap.components)
|
|
180
|
+
} else if (msg.type === 'DEBUG_EVENT') {
|
|
181
|
+
if (pausedRef.current) return
|
|
182
|
+
|
|
183
|
+
const debugEvent = msg.event as DebugEvent
|
|
184
|
+
|
|
185
|
+
// Update events list
|
|
186
|
+
setEvents(prev => {
|
|
187
|
+
const next = [...prev, debugEvent]
|
|
188
|
+
return next.length > maxEvents ? next.slice(-maxEvents) : next
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
// Update component snapshots based on event
|
|
192
|
+
updateComponentsFromEvent(debugEvent)
|
|
193
|
+
} else if (msg.type === 'DEBUG_SNAPSHOT') {
|
|
194
|
+
const snap = msg.snapshot as DebugSnapshot
|
|
195
|
+
setSnapshot(snap)
|
|
196
|
+
setComponents(snap.components)
|
|
197
|
+
}
|
|
198
|
+
} catch {
|
|
199
|
+
// Ignore parse errors
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
ws.onclose = () => {
|
|
204
|
+
setConnected(false)
|
|
205
|
+
setConnecting(false)
|
|
206
|
+
wsRef.current = null
|
|
207
|
+
|
|
208
|
+
// Don't reconnect if server told us debug is disabled
|
|
209
|
+
if (serverDisabledRef.current) return
|
|
210
|
+
|
|
211
|
+
// Auto-reconnect after 3 seconds
|
|
212
|
+
reconnectTimeoutRef.current = window.setTimeout(() => {
|
|
213
|
+
if (autoConnect) connect()
|
|
214
|
+
}, 3000)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
ws.onerror = () => {
|
|
218
|
+
setConnecting(false)
|
|
219
|
+
}
|
|
220
|
+
} catch {
|
|
221
|
+
setConnecting(false)
|
|
222
|
+
}
|
|
223
|
+
}, [getWsUrl, maxEvents, autoConnect])
|
|
224
|
+
|
|
225
|
+
// Update components from incoming events
|
|
226
|
+
const updateComponentsFromEvent = useCallback((event: DebugEvent) => {
|
|
227
|
+
setComponents(prev => {
|
|
228
|
+
switch (event.type) {
|
|
229
|
+
case 'COMPONENT_MOUNT': {
|
|
230
|
+
if (!event.componentId || !event.componentName) return prev
|
|
231
|
+
const existing = prev.find(c => c.componentId === event.componentId)
|
|
232
|
+
if (existing) return prev
|
|
233
|
+
return [...prev, {
|
|
234
|
+
componentId: event.componentId,
|
|
235
|
+
componentName: event.componentName,
|
|
236
|
+
debugLabel: (event.data.debugLabel as string) || undefined,
|
|
237
|
+
state: (event.data.initialState as Record<string, unknown>) || {},
|
|
238
|
+
rooms: event.data.room ? [event.data.room as string] : [],
|
|
239
|
+
mountedAt: event.timestamp,
|
|
240
|
+
lastActivity: event.timestamp,
|
|
241
|
+
actionCount: 0,
|
|
242
|
+
stateChangeCount: 0,
|
|
243
|
+
errorCount: 0
|
|
244
|
+
}]
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
case 'COMPONENT_UNMOUNT': {
|
|
248
|
+
return prev.filter(c => c.componentId !== event.componentId)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
case 'STATE_CHANGE': {
|
|
252
|
+
return prev.map(c => {
|
|
253
|
+
if (c.componentId !== event.componentId) return c
|
|
254
|
+
return {
|
|
255
|
+
...c,
|
|
256
|
+
state: (event.data.fullState as Record<string, unknown>) || c.state,
|
|
257
|
+
stateChangeCount: c.stateChangeCount + 1,
|
|
258
|
+
lastActivity: event.timestamp
|
|
259
|
+
}
|
|
260
|
+
})
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
case 'ACTION_CALL': {
|
|
264
|
+
return prev.map(c => {
|
|
265
|
+
if (c.componentId !== event.componentId) return c
|
|
266
|
+
return {
|
|
267
|
+
...c,
|
|
268
|
+
actionCount: c.actionCount + 1,
|
|
269
|
+
lastActivity: event.timestamp
|
|
270
|
+
}
|
|
271
|
+
})
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
case 'ACTION_ERROR':
|
|
275
|
+
case 'ERROR': {
|
|
276
|
+
return prev.map(c => {
|
|
277
|
+
if (c.componentId !== event.componentId) return c
|
|
278
|
+
return {
|
|
279
|
+
...c,
|
|
280
|
+
errorCount: c.errorCount + 1,
|
|
281
|
+
lastActivity: event.timestamp
|
|
282
|
+
}
|
|
283
|
+
})
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
case 'ROOM_JOIN': {
|
|
287
|
+
return prev.map(c => {
|
|
288
|
+
if (c.componentId !== event.componentId) return c
|
|
289
|
+
const roomId = event.data.roomId as string
|
|
290
|
+
if (c.rooms.includes(roomId)) return c
|
|
291
|
+
return { ...c, rooms: [...c.rooms, roomId] }
|
|
292
|
+
})
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
case 'ROOM_LEAVE': {
|
|
296
|
+
return prev.map(c => {
|
|
297
|
+
if (c.componentId !== event.componentId) return c
|
|
298
|
+
const roomId = event.data.roomId as string
|
|
299
|
+
return { ...c, rooms: c.rooms.filter(r => r !== roomId) }
|
|
300
|
+
})
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
default:
|
|
304
|
+
return prev.map(c => {
|
|
305
|
+
if (c.componentId !== event.componentId) return c
|
|
306
|
+
return { ...c, lastActivity: event.timestamp }
|
|
307
|
+
})
|
|
308
|
+
}
|
|
309
|
+
})
|
|
310
|
+
}, [])
|
|
311
|
+
|
|
312
|
+
// Disconnect
|
|
313
|
+
const disconnect = useCallback(() => {
|
|
314
|
+
if (reconnectTimeoutRef.current) {
|
|
315
|
+
clearTimeout(reconnectTimeoutRef.current)
|
|
316
|
+
reconnectTimeoutRef.current = null
|
|
317
|
+
}
|
|
318
|
+
if (wsRef.current) {
|
|
319
|
+
wsRef.current.close()
|
|
320
|
+
wsRef.current = null
|
|
321
|
+
}
|
|
322
|
+
setConnected(false)
|
|
323
|
+
setConnecting(false)
|
|
324
|
+
}, [])
|
|
325
|
+
|
|
326
|
+
// Reconnect
|
|
327
|
+
const reconnect = useCallback(() => {
|
|
328
|
+
disconnect()
|
|
329
|
+
setTimeout(() => connect(), 100)
|
|
330
|
+
}, [connect, disconnect])
|
|
331
|
+
|
|
332
|
+
// Filter events
|
|
333
|
+
const filteredEvents = events.filter(event => {
|
|
334
|
+
if (filter.componentId && event.componentId !== filter.componentId) return false
|
|
335
|
+
if (filter.types && filter.types.size > 0 && !filter.types.has(event.type)) return false
|
|
336
|
+
if (filter.search) {
|
|
337
|
+
const search = filter.search.toLowerCase()
|
|
338
|
+
const matchesData = JSON.stringify(event.data).toLowerCase().includes(search)
|
|
339
|
+
const matchesName = event.componentName?.toLowerCase().includes(search)
|
|
340
|
+
const matchesType = event.type.toLowerCase().includes(search)
|
|
341
|
+
if (!matchesData && !matchesName && !matchesType) return false
|
|
342
|
+
}
|
|
343
|
+
return true
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
// Selected component
|
|
347
|
+
const selectedComponent = selectedComponentId
|
|
348
|
+
? components.find(c => c.componentId === selectedComponentId) ?? null
|
|
349
|
+
: null
|
|
350
|
+
|
|
351
|
+
// Filter setter
|
|
352
|
+
const setFilter = useCallback((partial: Partial<DebugFilter>) => {
|
|
353
|
+
setFilterState(prev => ({ ...prev, ...partial }))
|
|
354
|
+
}, [])
|
|
355
|
+
|
|
356
|
+
// Toggle pause
|
|
357
|
+
const togglePause = useCallback(() => {
|
|
358
|
+
setPaused(prev => !prev)
|
|
359
|
+
}, [])
|
|
360
|
+
|
|
361
|
+
// Clear events
|
|
362
|
+
const clearEvents = useCallback(() => {
|
|
363
|
+
setEvents([])
|
|
364
|
+
}, [])
|
|
365
|
+
|
|
366
|
+
// Auto-connect
|
|
367
|
+
useEffect(() => {
|
|
368
|
+
if (autoConnect) connect()
|
|
369
|
+
return () => disconnect()
|
|
370
|
+
}, [autoConnect, connect, disconnect])
|
|
371
|
+
|
|
372
|
+
return {
|
|
373
|
+
connected,
|
|
374
|
+
connecting,
|
|
375
|
+
serverDisabled,
|
|
376
|
+
components,
|
|
377
|
+
events,
|
|
378
|
+
filteredEvents,
|
|
379
|
+
snapshot,
|
|
380
|
+
selectedComponentId,
|
|
381
|
+
selectedComponent,
|
|
382
|
+
selectComponent: setSelectedComponentId,
|
|
383
|
+
filter,
|
|
384
|
+
setFilter,
|
|
385
|
+
paused,
|
|
386
|
+
togglePause,
|
|
387
|
+
clearEvents,
|
|
388
|
+
reconnect,
|
|
389
|
+
eventCount: events.length,
|
|
390
|
+
componentCount: components.length
|
|
391
|
+
}
|
|
392
|
+
}
|
package/core/client/index.ts
CHANGED
|
@@ -29,3 +29,17 @@ export { useLiveUpload } from './hooks/useLiveUpload'
|
|
|
29
29
|
|
|
30
30
|
// Live Component Hook (API principal)
|
|
31
31
|
export { Live } from './components/Live'
|
|
32
|
+
|
|
33
|
+
// Live Component Debugger
|
|
34
|
+
export { LiveDebugger } from './components/LiveDebugger'
|
|
35
|
+
export type { LiveDebuggerProps } from './components/LiveDebugger'
|
|
36
|
+
export { useLiveDebugger } from './hooks/useLiveDebugger'
|
|
37
|
+
export type {
|
|
38
|
+
DebugEvent,
|
|
39
|
+
DebugEventType,
|
|
40
|
+
ComponentSnapshot,
|
|
41
|
+
DebugSnapshot,
|
|
42
|
+
DebugFilter,
|
|
43
|
+
UseLiveDebuggerReturn,
|
|
44
|
+
UseLiveDebuggerOptions
|
|
45
|
+
} from './hooks/useLiveDebugger'
|
|
@@ -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
|