create-fluxstack 1.9.1 → 1.12.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/.dockerignore +1 -2
- package/Dockerfile +8 -8
- package/LIVE_COMPONENTS_REVIEW.md +781 -0
- 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 +109 -156
- 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 -65
- 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 +242 -0
- package/app/client/src/live/UploadDemo.tsx +21 -0
- package/app/client/src/main.tsx +13 -10
- package/app/client/src/pages/ApiTestPage.tsx +108 -0
- package/app/client/src/pages/HomePage.tsx +76 -0
- package/app/client/src/vite-env.d.ts +1 -1
- package/app/server/app.ts +1 -4
- package/app/server/controllers/users.controller.ts +36 -44
- package/app/server/index.ts +24 -107
- 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 +285 -0
- package/app/server/live/LiveUpload.ts +81 -0
- package/app/server/live/register-components.ts +19 -19
- 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/bundler.ts +4 -1
- package/core/build/flux-plugins-generator.ts +325 -325
- package/core/build/index.ts +159 -27
- package/core/build/live-components-generator.ts +70 -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 -558
- package/core/cli/plugin-discovery.ts +2 -2
- package/core/client/LiveComponentsProvider.tsx +63 -17
- 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 -0
- package/core/client/hooks/state-validator.ts +1 -1
- package/core/client/hooks/useAuth.ts +48 -48
- package/core/client/hooks/useChunkedUpload.ts +170 -69
- 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 +18 -51
- 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 +227 -47
- package/core/framework/types.ts +2 -2
- package/core/index.ts +23 -4
- package/core/live/ComponentRegistry.ts +7 -3
- package/core/live/types.ts +77 -0
- package/core/plugins/built-in/index.ts +134 -131
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +242 -1074
- 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 +94 -306
- package/core/plugins/built-in/vite/vite-dev.ts +82 -0
- 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 +309 -21
- package/core/plugins/types.ts +106 -55
- package/core/server/framework.ts +66 -43
- package/core/server/index.ts +15 -16
- package/core/server/live/ComponentRegistry.ts +91 -75
- package/core/server/live/FileUploadManager.ts +41 -31
- 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 +41 -26
- package/core/server/live/index.ts +14 -0
- package/core/server/live/websocket-plugin.ts +233 -72
- 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 -260
- package/core/server/plugins/swagger.ts +33 -33
- 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 -218
- package/core/types/config.ts +56 -26
- package/core/types/index.ts +4 -4
- package/core/types/plugin.ts +107 -99
- package/core/types/types.ts +490 -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 -66
- 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/eslint.config.js +23 -23
- package/package.json +14 -15
- 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/plugins/crypto-auth/server/middlewares.ts +19 -19
- package/tsconfig.api-strict.json +16 -0
- package/tsconfig.json +10 -14
- package/{app/client/tsconfig.node.json → tsconfig.node.json} +1 -1
- 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/workspace.json +5 -5
- 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/tsconfig.app.json +0 -44
- 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/routes/env-test.ts +0 -110
- package/core/client/hooks/index.ts +0 -7
- package/core/client/hooks/useHybridLiveComponent.ts +0 -631
- package/core/client/hooks/useWebSocket.ts +0 -373
- package/core/config/env.ts +0 -546
- package/core/config/loader.ts +0 -522
- package/core/config/runtime-config.ts +0 -327
- package/core/config/validator.ts +0 -540
- package/core/server/backend-entry.ts +0 -51
- package/core/server/standalone.ts +0 -106
- package/core/utils/regenerate-files.ts +0 -69
- package/fluxstack.config.ts +0 -354
|
@@ -1,343 +1,131 @@
|
|
|
1
|
-
import type { FluxStack, PluginContext, RequestContext } from "
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import type { FluxStack, PluginContext, RequestContext } from "@core/plugins/types"
|
|
2
|
+
import { FLUXSTACK_VERSION } from "@core/utils/version"
|
|
3
|
+
import { clientConfig } from '@config'
|
|
4
|
+
import { pluginsConfig } from '@config'
|
|
5
|
+
import { isDevelopment } from "@core/utils/helpers"
|
|
6
|
+
import { join } from "path"
|
|
7
|
+
import { statSync, existsSync } from "fs"
|
|
5
8
|
|
|
6
9
|
type Plugin = FluxStack.Plugin
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
const PLUGIN_PRIORITY = 800
|
|
12
|
+
const INDEX_FILE = "index.html"
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
/** Create static file handler with cached base directory */
|
|
15
|
+
function createStaticFallback() {
|
|
16
|
+
// Discover base directory once
|
|
17
|
+
const baseDir = existsSync('client') ? 'client'
|
|
18
|
+
: existsSync('dist/client') ? 'dist/client'
|
|
19
|
+
: clientConfig.build.outDir ?? 'dist/client'
|
|
20
|
+
|
|
21
|
+
return (c: { request?: Request }) => {
|
|
22
|
+
const req = c.request
|
|
23
|
+
if (!req) return
|
|
24
|
+
|
|
25
|
+
let pathname = decodeURIComponent(new URL(req.url).pathname)
|
|
26
|
+
if (pathname === '/' || pathname === '') {
|
|
27
|
+
pathname = `/${INDEX_FILE}`
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Try to serve the requested file
|
|
31
|
+
const filePath = join(baseDir, pathname)
|
|
32
|
+
try {
|
|
33
|
+
if (statSync(filePath).isFile()) {
|
|
34
|
+
return Bun.file(filePath)
|
|
35
|
+
}
|
|
36
|
+
} catch {}
|
|
37
|
+
|
|
38
|
+
// SPA fallback: serve index.html
|
|
39
|
+
const indexPath = join(baseDir, INDEX_FILE)
|
|
40
|
+
try {
|
|
41
|
+
statSync(indexPath)
|
|
42
|
+
return Bun.file(indexPath)
|
|
43
|
+
} catch {}
|
|
44
|
+
}
|
|
20
45
|
}
|
|
21
46
|
|
|
22
|
-
/**
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
47
|
+
/** Proxy request to Vite dev server */
|
|
48
|
+
async function proxyToVite(ctx: RequestContext): Promise<void> {
|
|
49
|
+
const { host, port } = clientConfig.vite
|
|
50
|
+
|
|
26
51
|
try {
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
52
|
+
// Parse URL (handle relative URLs)
|
|
53
|
+
let url: URL
|
|
54
|
+
try {
|
|
55
|
+
url = new URL(ctx.request.url)
|
|
56
|
+
} catch {
|
|
57
|
+
const reqHost = ctx.request.headers.get('host') || 'localhost'
|
|
58
|
+
const protocol = ctx.request.headers.get('x-forwarded-proto') || 'http'
|
|
59
|
+
url = new URL(ctx.request.url, `${protocol}://${reqHost}`)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const response = await fetch(`http://${host}:${port}${ctx.path}${url.search}`, {
|
|
63
|
+
method: ctx.method,
|
|
64
|
+
headers: ctx.headers,
|
|
65
|
+
body: ctx.method !== 'GET' && ctx.method !== 'HEAD' ? ctx.request.body : undefined
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
ctx.handled = true
|
|
69
|
+
ctx.response = new Response(await response.arrayBuffer(), {
|
|
70
|
+
status: response.status,
|
|
71
|
+
statusText: response.statusText,
|
|
72
|
+
headers: response.headers
|
|
73
|
+
})
|
|
74
|
+
} catch (error) {
|
|
75
|
+
if (clientConfig.vite.enableLogging) {
|
|
76
|
+
console.warn(`Vite proxy error: ${error}`)
|
|
77
|
+
}
|
|
34
78
|
}
|
|
35
79
|
}
|
|
36
80
|
|
|
37
81
|
export const vitePlugin: Plugin = {
|
|
38
82
|
name: "vite",
|
|
39
83
|
version: FLUXSTACK_VERSION,
|
|
40
|
-
description: "
|
|
84
|
+
description: "Vite integration plugin for FluxStack",
|
|
41
85
|
author: "FluxStack Team",
|
|
42
|
-
priority:
|
|
86
|
+
priority: PLUGIN_PRIORITY,
|
|
43
87
|
category: "development",
|
|
44
88
|
tags: ["vite", "development", "hot-reload"],
|
|
45
89
|
dependencies: [],
|
|
46
90
|
|
|
47
91
|
setup: async (context: PluginContext) => {
|
|
48
|
-
if (!
|
|
49
|
-
context.logger.debug('Vite plugin disabled
|
|
92
|
+
if (!pluginsConfig.viteEnabled) {
|
|
93
|
+
context.logger.debug('Vite plugin disabled')
|
|
50
94
|
return
|
|
51
95
|
}
|
|
52
96
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
// Import group logger utilities
|
|
57
|
-
const { startGroup, endGroup, logInGroup } = await import('@/core/utils/logger/group-logger')
|
|
58
|
-
|
|
59
|
-
try {
|
|
60
|
-
// Start Vite dev server programmatically (silently)
|
|
61
|
-
viteServer = await createServer({
|
|
62
|
-
configFile: './vite.config.ts',
|
|
63
|
-
// Don't override root - let vite.config.ts handle it
|
|
64
|
-
server: {
|
|
65
|
-
port: vitePort,
|
|
66
|
-
host: viteHost,
|
|
67
|
-
strictPort: true
|
|
68
|
-
},
|
|
69
|
-
logLevel: 'silent' // Suppress all Vite logs
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
await viteServer.listen()
|
|
73
|
-
|
|
74
|
-
context.logger.debug(`Vite server started on ${viteHost}:${vitePort} (internal proxy)`)
|
|
75
|
-
context.logger.debug('Hot reload coordination active')
|
|
76
|
-
|
|
77
|
-
// Store Vite config in context for later use
|
|
78
|
-
; (context as any).viteConfig = {
|
|
79
|
-
port: vitePort,
|
|
80
|
-
host: viteHost,
|
|
81
|
-
server: viteServer
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Setup cleanup on process exit
|
|
85
|
-
const cleanup = async () => {
|
|
86
|
-
if (viteServer) {
|
|
87
|
-
context.logger.debug('🛑 Stopping Vite server...')
|
|
88
|
-
await viteServer.close()
|
|
89
|
-
viteServer = null
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
process.on('SIGINT', cleanup)
|
|
94
|
-
process.on('SIGTERM', cleanup)
|
|
95
|
-
process.on('exit', cleanup)
|
|
96
|
-
|
|
97
|
-
} catch (error) {
|
|
98
|
-
// Check if error is related to port already in use
|
|
99
|
-
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
100
|
-
const isPortInUse = errorMessage.includes('EADDRINUSE') ||
|
|
101
|
-
errorMessage.includes('address already in use') ||
|
|
102
|
-
errorMessage.includes('Port') && errorMessage.includes('is in use')
|
|
103
|
-
|
|
104
|
-
if (isPortInUse) {
|
|
105
|
-
endGroup()
|
|
106
|
-
console.log('') // Separator line
|
|
107
|
-
context.logger.error(`❌ Failed to start Vite: Port ${vitePort} is already in use`)
|
|
108
|
-
context.logger.info(`💡 Try one of these solutions:`)
|
|
109
|
-
context.logger.info(` 1. Stop the process using port ${vitePort}`)
|
|
110
|
-
context.logger.info(` 2. Change VITE_PORT in your .env file`)
|
|
111
|
-
context.logger.info(` 3. Kill the process: ${process.platform === 'win32' ? `netstat -ano | findstr :${vitePort}` : `lsof -ti:${vitePort} | xargs kill -9`}`)
|
|
112
|
-
process.exit(1)
|
|
113
|
-
} else {
|
|
114
|
-
context.logger.error('❌ Failed to start Vite server:', errorMessage)
|
|
115
|
-
context.logger.debug('Full error:', error)
|
|
116
|
-
context.logger.debug('⚠️ Falling back to monitoring mode...')
|
|
117
|
-
|
|
118
|
-
// Fallback to monitoring if programmatic start fails
|
|
119
|
-
; (context as any).viteConfig = {
|
|
120
|
-
port: vitePort,
|
|
121
|
-
host: viteHost
|
|
122
|
-
}
|
|
123
|
-
monitorVite(context, viteHost, vitePort)
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
},
|
|
127
|
-
|
|
128
|
-
onServerStart: async (context: PluginContext) => {
|
|
129
|
-
const viteConfig = (context as any).viteConfig
|
|
130
|
-
|
|
131
|
-
if (DEFAULTS.enabled && viteConfig) {
|
|
132
|
-
context.logger.debug(`Vite integration active - monitoring ${viteConfig.host}:${viteConfig.port}`)
|
|
133
|
-
}
|
|
134
|
-
},
|
|
135
|
-
|
|
136
|
-
onBeforeRoute: async (requestContext: RequestContext) => {
|
|
137
|
-
// Skip API routes and swagger - let them be handled by backend
|
|
138
|
-
if (requestContext.path.startsWith("/api") || requestContext.path.startsWith("/swagger")) {
|
|
97
|
+
if (!isDevelopment()) {
|
|
98
|
+
context.logger.debug("Production mode: static file serving enabled")
|
|
99
|
+
context.app.all('*', createStaticFallback())
|
|
139
100
|
return
|
|
140
101
|
}
|
|
141
102
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
requestContext.path.startsWith("/node_modules") || // Direct node_modules access
|
|
146
|
-
requestContext.path.includes("/.vite/") || // Vite cache and deps
|
|
147
|
-
requestContext.path.endsWith(".js.map") || // Source maps
|
|
148
|
-
requestContext.path.endsWith(".css.map")) { // CSS source maps
|
|
149
|
-
|
|
150
|
-
// Use fixed configuration for Vite proxy
|
|
151
|
-
const viteHost = "localhost"
|
|
152
|
-
const vitePort = 5173
|
|
153
|
-
|
|
154
|
-
try {
|
|
155
|
-
const url = parseRequestURL(requestContext.request)
|
|
156
|
-
const viteUrl = `http://${viteHost}:${vitePort}${requestContext.path}${url.search}`
|
|
157
|
-
|
|
158
|
-
// Forward request to Vite
|
|
159
|
-
const response = await fetch(viteUrl, {
|
|
160
|
-
method: requestContext.method,
|
|
161
|
-
headers: requestContext.headers,
|
|
162
|
-
body: requestContext.method !== 'GET' && requestContext.method !== 'HEAD' ? requestContext.request.body : undefined
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
// Return the Vite response
|
|
166
|
-
const body = await response.arrayBuffer()
|
|
103
|
+
const { setupViteDev } = await import('./vite-dev')
|
|
104
|
+
await setupViteDev(context)
|
|
105
|
+
},
|
|
167
106
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
status: response.status,
|
|
171
|
-
statusText: response.statusText,
|
|
172
|
-
headers: response.headers
|
|
173
|
-
})
|
|
107
|
+
onServerStart: async (context: PluginContext) => {
|
|
108
|
+
if (!pluginsConfig.viteEnabled) return
|
|
174
109
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
// Only log if explicitly enabled for debugging
|
|
178
|
-
const { clientConfig } = await import('@/config/client.config')
|
|
179
|
-
if (clientConfig.vite.enableLogging) {
|
|
180
|
-
console.warn(`Vite proxy error: ${viteError}`)
|
|
181
|
-
}
|
|
182
|
-
}
|
|
110
|
+
if (!isDevelopment()) {
|
|
111
|
+
context.logger.debug('Static files ready')
|
|
183
112
|
return
|
|
184
113
|
}
|
|
185
114
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const vitePort = 5173
|
|
189
|
-
|
|
190
|
-
try {
|
|
191
|
-
const url = parseRequestURL(requestContext.request)
|
|
192
|
-
const viteUrl = `http://${viteHost}:${vitePort}${requestContext.path}${url.search}`
|
|
193
|
-
|
|
194
|
-
// Forward request to Vite
|
|
195
|
-
const response = await fetch(viteUrl, {
|
|
196
|
-
method: requestContext.method,
|
|
197
|
-
headers: requestContext.headers,
|
|
198
|
-
body: requestContext.method !== 'GET' && requestContext.method !== 'HEAD' ? requestContext.request.body : undefined
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
// If Vite responds successfully, handle the request
|
|
202
|
-
if (response.ok || response.status < 500) {
|
|
203
|
-
// Return a proper Response object with all headers and status
|
|
204
|
-
const body = await response.arrayBuffer()
|
|
205
|
-
|
|
206
|
-
requestContext.handled = true
|
|
207
|
-
requestContext.response = new Response(body, {
|
|
208
|
-
status: response.status,
|
|
209
|
-
statusText: response.statusText,
|
|
210
|
-
headers: response.headers
|
|
211
|
-
})
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
} catch (viteError) {
|
|
215
|
-
// If Vite fails, let the request continue to normal routing (will become 404)
|
|
216
|
-
// Only log if explicitly enabled for debugging
|
|
217
|
-
const { clientConfig } = await import('@/config/client.config')
|
|
218
|
-
if (clientConfig.vite.enableLogging) {
|
|
219
|
-
console.warn(`Vite proxy error: ${viteError}`)
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Monitor Vite server status with automatic port detection
|
|
226
|
-
async function monitorVite(
|
|
227
|
-
context: PluginContext,
|
|
228
|
-
host: string,
|
|
229
|
-
initialPort: number
|
|
230
|
-
) {
|
|
231
|
-
let retries = 0
|
|
232
|
-
let isConnected = false
|
|
233
|
-
let actualPort = initialPort
|
|
234
|
-
let portDetected = false
|
|
235
|
-
|
|
236
|
-
const checkVite = async () => {
|
|
237
|
-
try {
|
|
238
|
-
// If we haven't found the correct port yet, try to detect it
|
|
239
|
-
if (!portDetected) {
|
|
240
|
-
const detectedPort = await detectVitePort(host, initialPort)
|
|
241
|
-
if (detectedPort !== null) {
|
|
242
|
-
actualPort = detectedPort
|
|
243
|
-
portDetected = true
|
|
244
|
-
// Update the context with the detected port
|
|
245
|
-
if ((context as any).viteConfig) {
|
|
246
|
-
; (context as any).viteConfig.port = actualPort
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const isRunning = await checkViteRunning(host, actualPort, DEFAULTS.timeout)
|
|
252
|
-
|
|
253
|
-
if (isRunning && !isConnected) {
|
|
254
|
-
isConnected = true
|
|
255
|
-
retries = 0
|
|
256
|
-
if (actualPort !== initialPort) {
|
|
257
|
-
context.logger.debug(`✓ Vite server detected on ${host}:${actualPort} (auto-detected from port ${initialPort})`)
|
|
258
|
-
} else {
|
|
259
|
-
context.logger.debug(`✓ Vite server detected on ${host}:${actualPort}`)
|
|
260
|
-
}
|
|
261
|
-
context.logger.debug("Hot reload coordination active")
|
|
262
|
-
} else if (!isRunning && isConnected) {
|
|
263
|
-
isConnected = false
|
|
264
|
-
context.logger.warn(`✗ Vite server disconnected from ${host}:${actualPort}`)
|
|
265
|
-
// Reset port detection when disconnected
|
|
266
|
-
portDetected = false
|
|
267
|
-
actualPort = initialPort
|
|
268
|
-
} else if (!isRunning) {
|
|
269
|
-
retries++
|
|
270
|
-
if (retries <= DEFAULTS.maxRetries) {
|
|
271
|
-
if (portDetected) {
|
|
272
|
-
context.logger.debug(`Waiting for Vite server on ${host}:${actualPort}... (${retries}/${DEFAULTS.maxRetries})`)
|
|
273
|
-
} else {
|
|
274
|
-
context.logger.debug(`Detecting Vite server port... (${retries}/${DEFAULTS.maxRetries})`)
|
|
275
|
-
}
|
|
276
|
-
} else if (retries === DEFAULTS.maxRetries + 1) {
|
|
277
|
-
context.logger.warn(`Vite server not found after ${DEFAULTS.maxRetries} attempts. Development features may be limited.`)
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
} catch (error) {
|
|
281
|
-
if (isConnected) {
|
|
282
|
-
context.logger.error('Error checking Vite server status', { error })
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// Continue monitoring
|
|
287
|
-
setTimeout(checkVite, DEFAULTS.checkInterval)
|
|
288
|
-
}
|
|
115
|
+
context.logger.debug(`Vite active - ${clientConfig.vite.host}:${clientConfig.vite.port}`)
|
|
116
|
+
},
|
|
289
117
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
}
|
|
118
|
+
onBeforeRoute: async (ctx: RequestContext) => {
|
|
119
|
+
if (!isDevelopment()) return
|
|
293
120
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const portsToTry = [
|
|
298
|
-
startPort,
|
|
299
|
-
startPort + 1,
|
|
300
|
-
startPort + 2,
|
|
301
|
-
startPort + 3,
|
|
302
|
-
5174, // Common Vite alternative
|
|
303
|
-
5175,
|
|
304
|
-
5176,
|
|
305
|
-
3000, // Sometimes Vite might use this
|
|
306
|
-
4173 // Another common alternative
|
|
307
|
-
]
|
|
121
|
+
const shouldSkip = (pluginsConfig.viteExcludePaths ?? []).some(prefix =>
|
|
122
|
+
ctx.path === prefix || ctx.path.startsWith(prefix + '/')
|
|
123
|
+
)
|
|
308
124
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
const isRunning = await checkViteRunning(host, port, 1000)
|
|
312
|
-
if (isRunning) {
|
|
313
|
-
return port
|
|
314
|
-
}
|
|
315
|
-
} catch (error) {
|
|
316
|
-
// Continue trying other ports
|
|
125
|
+
if (!shouldSkip) {
|
|
126
|
+
await proxyToVite(ctx)
|
|
317
127
|
}
|
|
318
128
|
}
|
|
319
|
-
|
|
320
|
-
return null
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// Check if Vite is running
|
|
324
|
-
async function checkViteRunning(host: string, port: number, timeout: number = 1000): Promise<boolean> {
|
|
325
|
-
try {
|
|
326
|
-
const controller = new AbortController()
|
|
327
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout)
|
|
328
|
-
|
|
329
|
-
const response = await fetch(`http://${host}:${port}`, {
|
|
330
|
-
signal: controller.signal,
|
|
331
|
-
method: 'HEAD' // Use HEAD to minimize data transfer
|
|
332
|
-
})
|
|
333
|
-
|
|
334
|
-
clearTimeout(timeoutId)
|
|
335
|
-
return response.status >= 200 && response.status < 500
|
|
336
|
-
} catch (error) {
|
|
337
|
-
return false
|
|
338
|
-
}
|
|
339
129
|
}
|
|
340
130
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
export default vitePlugin
|
|
131
|
+
export default vitePlugin
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { PluginContext } from "@core/plugins/types"
|
|
2
|
+
import { clientConfig } from '@config'
|
|
3
|
+
import type { LogLevel } from "vite"
|
|
4
|
+
import conf from "@/vite.config"
|
|
5
|
+
// Dynamic import t@ype for vite
|
|
6
|
+
type ViteDevServer = Awaited<ReturnType<typeof import('vite')['createServer']>>
|
|
7
|
+
|
|
8
|
+
// Store vite server instance
|
|
9
|
+
let viteServer: ViteDevServer | null = null
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Setup Vite development server
|
|
13
|
+
* This file is only imported in development mode
|
|
14
|
+
*/
|
|
15
|
+
export async function setupViteDev(context: PluginContext): Promise<void> {
|
|
16
|
+
const vitePort = clientConfig.vite.port || 5173
|
|
17
|
+
const viteHost = clientConfig.vite.host || "localhost"
|
|
18
|
+
const logLevel = clientConfig.vite.logLevel as LogLevel
|
|
19
|
+
// Import group logger utilities
|
|
20
|
+
const { endGroup } = await import('@core/utils/logger/group-logger')
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
// Dynamic import of vite
|
|
24
|
+
const { createServer } = await import('vite')
|
|
25
|
+
// Start Vite dev server programmatically (silently)
|
|
26
|
+
viteServer = await createServer({
|
|
27
|
+
configFile: './vite.config.ts',
|
|
28
|
+
server: {
|
|
29
|
+
port: vitePort,
|
|
30
|
+
host: viteHost,
|
|
31
|
+
strictPort: true
|
|
32
|
+
},
|
|
33
|
+
logLevel: logLevel
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
await viteServer.listen()
|
|
37
|
+
|
|
38
|
+
context.logger.debug(`Vite server started on ${viteHost}:${vitePort} (internal proxy)`)
|
|
39
|
+
context.logger.debug('Hot reload coordination active')
|
|
40
|
+
|
|
41
|
+
// Store Vite config in context for later use
|
|
42
|
+
;(context as any).viteConfig = {
|
|
43
|
+
port: vitePort,
|
|
44
|
+
host: viteHost,
|
|
45
|
+
server: viteServer
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Setup cleanup on process exit
|
|
49
|
+
const cleanup = async () => {
|
|
50
|
+
if (viteServer) {
|
|
51
|
+
context.logger.debug('🛑 Stopping Vite server...')
|
|
52
|
+
await viteServer.close()
|
|
53
|
+
viteServer = null
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
process.on('SIGINT', cleanup)
|
|
58
|
+
process.on('SIGTERM', cleanup)
|
|
59
|
+
process.on('exit', cleanup)
|
|
60
|
+
|
|
61
|
+
} catch (error) {
|
|
62
|
+
// Check if error is related to port already in use
|
|
63
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
64
|
+
const isPortInUse = errorMessage.includes('EADDRINUSE') ||
|
|
65
|
+
errorMessage.includes('address already in use') ||
|
|
66
|
+
errorMessage.includes('Port') && errorMessage.includes('is in use')
|
|
67
|
+
|
|
68
|
+
if (isPortInUse) {
|
|
69
|
+
endGroup()
|
|
70
|
+
console.log('') // Separator line
|
|
71
|
+
context.logger.error(`❌ Failed to start Vite: Port ${vitePort} is already in use`)
|
|
72
|
+
context.logger.info(`💡 Try one of these solutions:`)
|
|
73
|
+
context.logger.info(` 1. Stop the process using port ${vitePort}`)
|
|
74
|
+
context.logger.info(` 2. Change VITE_PORT in your .env file`)
|
|
75
|
+
context.logger.info(` 3. Kill the process: ${process.platform === 'win32' ? `netstat -ano | findstr :${vitePort}` : `lsof -ti:${vitePort} | xargs kill -9`}`)
|
|
76
|
+
process.exit(1)
|
|
77
|
+
} else {
|
|
78
|
+
context.logger.error('❌ Failed to start Vite server:', errorMessage)
|
|
79
|
+
context.logger.debug('Full error:', error)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
package/core/plugins/config.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { FluxStack, PluginConfigSchema, PluginValidationResult } from "./types"
|
|
7
|
-
import type { FluxStackConfig } from "
|
|
8
|
-
import type { Logger } from "
|
|
7
|
+
import type { FluxStackConfig } from "@config"
|
|
8
|
+
import type { Logger } from "@core/utils/logger/index"
|
|
9
9
|
|
|
10
10
|
type Plugin = FluxStack.Plugin
|
|
11
11
|
|
|
@@ -61,19 +61,21 @@ export class DefaultPluginConfigManager implements PluginConfigManager {
|
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
63
|
* Get plugin configuration from main config
|
|
64
|
+
* @deprecated Plugin configs are now directly accessed from config.plugins
|
|
64
65
|
*/
|
|
65
66
|
getPluginConfig(pluginName: string, config: FluxStackConfig): any {
|
|
66
|
-
|
|
67
|
+
// Plugin configs are now accessed directly from config.plugins
|
|
68
|
+
// Example: config.plugins.swaggerEnabled
|
|
69
|
+
return {}
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
/**
|
|
70
73
|
* Set plugin configuration in main config
|
|
74
|
+
* @deprecated Plugin configs are now set via environment variables and config files
|
|
71
75
|
*/
|
|
72
76
|
setPluginConfig(pluginName: string, pluginConfig: any, config: FluxStackConfig): void {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
config.plugins.config[pluginName] = pluginConfig
|
|
77
|
+
// Plugin configs are now set via environment variables and config files
|
|
78
|
+
// This function is deprecated and does nothing
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
/**
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { existsSync, readFileSync, writeFileSync } from 'fs'
|
|
7
7
|
import { join, resolve } from 'path'
|
|
8
8
|
import { execSync } from 'child_process'
|
|
9
|
-
import type { Logger } from '
|
|
9
|
+
import type { Logger } from '@core/utils/logger'
|
|
10
10
|
|
|
11
11
|
export interface PluginDependency {
|
|
12
12
|
name: string
|
|
@@ -230,6 +230,36 @@ export class PluginDependencyManager {
|
|
|
230
230
|
}
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Instalar dependências diretamente em um path específico
|
|
235
|
+
*/
|
|
236
|
+
async installDependenciesInPath(pluginPath: string, dependencies: Record<string, string>): Promise<void> {
|
|
237
|
+
if (!this.config.autoInstall) {
|
|
238
|
+
this.logger?.debug('Auto-instalação desabilitada')
|
|
239
|
+
return
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (Object.keys(dependencies).length === 0) {
|
|
243
|
+
return
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const pluginDeps: PluginDependency[] = Object.entries(dependencies).map(([name, version]) => ({
|
|
247
|
+
name,
|
|
248
|
+
version,
|
|
249
|
+
type: 'dependency'
|
|
250
|
+
}))
|
|
251
|
+
|
|
252
|
+
this.logger?.debug(`📦 Instalando ${pluginDeps.length} dependência(s) em ${pluginPath}`)
|
|
253
|
+
|
|
254
|
+
try {
|
|
255
|
+
await this.installPluginDependenciesLocally(pluginPath, pluginDeps)
|
|
256
|
+
this.logger?.debug(`✅ Dependências instaladas com sucesso em ${pluginPath}`)
|
|
257
|
+
} catch (error) {
|
|
258
|
+
this.logger?.error(`❌ Erro ao instalar dependências em ${pluginPath}`, { error })
|
|
259
|
+
throw error
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
233
263
|
/**
|
|
234
264
|
* Encontrar diretório de um plugin pelo nome
|
|
235
265
|
*/
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { FluxStack, PluginManifest, PluginLoadResult, PluginDiscoveryOptions } from "./types"
|
|
7
|
-
import type { Logger } from "
|
|
7
|
+
import type { Logger } from "@core/utils/logger/index"
|
|
8
8
|
import { readdir, readFile } from "fs/promises"
|
|
9
9
|
import { join, resolve } from "path"
|
|
10
10
|
import { existsSync } from "fs"
|
|
@@ -306,12 +306,24 @@ export class PluginDiscovery {
|
|
|
306
306
|
* Validate if an object is a valid plugin
|
|
307
307
|
*/
|
|
308
308
|
private isValidPlugin(plugin: any): plugin is Plugin {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
309
|
+
if (!plugin || typeof plugin !== 'object' || typeof plugin.name !== 'string' || plugin.name.length === 0) {
|
|
310
|
+
return false
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const hookNames = [
|
|
314
|
+
'setup', 'onConfigLoad', 'onBeforeServerStart', 'onServerStart',
|
|
315
|
+
'onAfterServerStart', 'onBeforeServerStop', 'onServerStop',
|
|
316
|
+
'onRequest', 'onResponse', 'onError'
|
|
317
|
+
]
|
|
318
|
+
|
|
319
|
+
for (const hook of hookNames) {
|
|
320
|
+
if (hook in plugin && typeof plugin[hook] !== 'function') {
|
|
321
|
+
this.logger?.warn(`Plugin "${plugin.name}" has invalid hook "${hook}" (expected function, got ${typeof plugin[hook]})`)
|
|
322
|
+
return false
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return true
|
|
315
327
|
}
|
|
316
328
|
|
|
317
329
|
/**
|
package/core/plugins/executor.ts
CHANGED
|
@@ -10,8 +10,8 @@ import type {
|
|
|
10
10
|
PluginPriority,
|
|
11
11
|
HookExecutionOptions
|
|
12
12
|
} from "./types"
|
|
13
|
-
import type { Logger } from "
|
|
14
|
-
import { FluxStackError } from "
|
|
13
|
+
import type { Logger } from "@core/utils/logger/index"
|
|
14
|
+
import { FluxStackError } from "@core/utils/errors"
|
|
15
15
|
|
|
16
16
|
export interface PluginExecutionPlan {
|
|
17
17
|
hook: PluginHook
|