create-fluxstack 1.17.1 → 1.18.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/resources/live-auth.md +462 -465
- package/app/client/.live-stubs/LiveAdminPanel.js +15 -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/LivePingPong.js +10 -0
- package/app/client/.live-stubs/LiveRoomChat.js +11 -0
- package/app/client/.live-stubs/LiveSharedCounter.js +10 -0
- package/app/client/.live-stubs/LiveUpload.js +15 -0
- package/app/client/src/App.tsx +45 -3
- package/app/client/src/components/AppLayout.tsx +10 -1
- package/app/client/src/components/ErrorBoundary.tsx +117 -0
- package/app/client/src/components/LiveErrorBoundary.tsx +87 -0
- package/app/client/src/components/LiveUploadWidget.tsx +10 -14
- package/app/client/src/lib/eden-api.ts +6 -0
- package/app/client/src/lib/plugin-hooks.ts +82 -0
- package/app/client/src/live/AuthDemo.tsx +0 -1
- package/app/client/src/live/FormDemo.tsx +1 -1
- package/app/client/src/live/PingPongDemo.tsx +4 -1
- package/app/client/src/live/RoomChatDemo.tsx +90 -50
- package/app/client/src/live/SharedCounterDemo.tsx +5 -0
- package/app/server/auth/AuthManager.ts +24 -0
- package/app/server/auth/contracts.ts +12 -1
- package/app/server/auth/errors.ts +84 -0
- package/app/server/auth/guards/TokenGuard.ts +5 -2
- package/app/server/auth/index.ts +1 -1
- package/app/server/auth/providers/InMemoryProvider.ts +1 -1
- package/app/server/index.ts +3 -4
- package/app/server/live/LiveAdminPanel.ts +8 -8
- package/app/server/live/LiveForm.ts +1 -1
- package/app/server/live/LiveProtectedChat.ts +5 -5
- package/app/server/live/LiveRoomChat.ts +50 -28
- package/app/server/live/LiveUpload.ts +17 -3
- package/app/server/live/auto-generated-components.ts +26 -0
- package/app/server/live/rooms/ChatRoom.ts +17 -2
- package/app/server/routes/auth.routes.ts +29 -20
- package/app/server/routes/index.ts +9 -0
- package/app/server/routes/room.routes.ts +6 -6
- package/config/index.ts +3 -3
- package/config/system/app.config.ts +1 -1
- package/config/system/auth.config.ts +1 -1
- package/config/system/build.config.ts +8 -6
- package/config/system/client.config.ts +6 -4
- package/config/system/database.config.ts +1 -1
- package/config/system/logger.config.ts +1 -1
- package/config/system/monitoring.config.ts +6 -4
- package/config/system/plugins.config.ts +1 -1
- package/config/system/runtime.config.ts +1 -1
- package/config/system/server.config.ts +1 -1
- package/config/system/services.config.ts +1 -1
- package/config/system/session.config.ts +3 -3
- package/config/system/system.config.ts +1 -1
- package/core/build/vite-plugins.ts +3 -2
- package/core/cli/generators/plugin.ts +1 -1
- package/core/config/index.ts +8 -1
- package/core/framework/server.ts +7 -3
- package/core/index.ts +1 -1
- package/core/plugins/index.ts +1 -1
- package/core/plugins/manager.ts +5 -1
- package/core/plugins/types.ts +17 -1
- package/core/server/index.ts +5 -2
- package/core/server/live/index.ts +8 -71
- package/core/server/plugin-client-hooks.ts +97 -0
- package/core/types/types.ts +1 -0
- package/core/utils/version.ts +1 -1
- package/create-fluxstack.ts +1 -1
- package/package.json +8 -5
- package/src/client/components/ui/StatusBadge.tsx +23 -0
- package/core/utils/config-schema.ts +0 -480
- package/core/utils/env.ts +0 -305
- package/plugins/crypto-auth/README.md +0 -788
- package/plugins/crypto-auth/ai-context.md +0 -1282
- package/plugins/crypto-auth/cli/make-protected-route.command.ts +0 -383
- package/plugins/crypto-auth/client/CryptoAuthClient.ts +0 -302
- package/plugins/crypto-auth/client/components/AuthProvider.tsx +0 -131
- package/plugins/crypto-auth/client/components/LoginButton.tsx +0 -138
- package/plugins/crypto-auth/client/components/ProtectedRoute.tsx +0 -89
- package/plugins/crypto-auth/client/components/index.ts +0 -12
- package/plugins/crypto-auth/client/index.ts +0 -12
- package/plugins/crypto-auth/config/index.ts +0 -34
- package/plugins/crypto-auth/index.ts +0 -173
- package/plugins/crypto-auth/package.json +0 -66
- package/plugins/crypto-auth/server/AuthMiddleware.ts +0 -181
- package/plugins/crypto-auth/server/CryptoAuthLiveProvider.ts +0 -58
- package/plugins/crypto-auth/server/CryptoAuthService.ts +0 -186
- package/plugins/crypto-auth/server/index.ts +0 -25
- package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +0 -66
- package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +0 -26
- package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +0 -77
- package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +0 -45
- package/plugins/crypto-auth/server/middlewares/helpers.ts +0 -155
- package/plugins/crypto-auth/server/middlewares/index.ts +0 -22
- package/plugins/crypto-auth/server/middlewares.ts +0 -19
package/core/config/index.ts
CHANGED
|
@@ -9,7 +9,14 @@
|
|
|
9
9
|
|
|
10
10
|
import type { FluxStackConfig } from '@config'
|
|
11
11
|
import { fluxStackConfig } from '@config'
|
|
12
|
-
import {
|
|
12
|
+
import { env } from '@fluxstack/config'
|
|
13
|
+
|
|
14
|
+
const nodeEnv = (): string => env.get('NODE_ENV', 'development')
|
|
15
|
+
const helpers = {
|
|
16
|
+
isDevelopment: () => nodeEnv() === 'development',
|
|
17
|
+
isProduction: () => nodeEnv() === 'production',
|
|
18
|
+
isTest: () => nodeEnv() === 'test',
|
|
19
|
+
}
|
|
13
20
|
import { logger } from '../utils/logger'
|
|
14
21
|
|
|
15
22
|
// ============================================================================
|
package/core/framework/server.ts
CHANGED
|
@@ -7,11 +7,12 @@ import { fluxStackConfig } from "@config"
|
|
|
7
7
|
import { getEnvironmentInfo } from "@core/config"
|
|
8
8
|
import { logger, type Logger } from "@core/utils/logger"
|
|
9
9
|
import { displayStartupBanner, type StartupInfo } from "@core/utils/logger/startup-banner"
|
|
10
|
-
import {
|
|
10
|
+
import { liveServer } 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 { createHash } from "crypto"
|
|
14
14
|
import { createPluginUtils } from "@core/plugins/config"
|
|
15
|
+
import { pluginClientHooks } from "@core/server/plugin-client-hooks"
|
|
15
16
|
import type { Plugin } from "@core/plugins"
|
|
16
17
|
|
|
17
18
|
export class FluxStackFramework {
|
|
@@ -142,7 +143,10 @@ export class FluxStackFramework {
|
|
|
142
143
|
config: fullConfig,
|
|
143
144
|
logger: pluginLogger,
|
|
144
145
|
app: this.app,
|
|
145
|
-
utils: pluginUtils
|
|
146
|
+
utils: pluginUtils,
|
|
147
|
+
clientHooks: {
|
|
148
|
+
register: (hookName: string, jsCode: string) => pluginClientHooks.register(hookName, jsCode)
|
|
149
|
+
}
|
|
146
150
|
}
|
|
147
151
|
|
|
148
152
|
// Initialize plugin manager
|
|
@@ -826,7 +830,7 @@ export class FluxStackFramework {
|
|
|
826
830
|
vitePort: this.cfg.client?.port,
|
|
827
831
|
viteEmbedded: vitePluginActive, // Vite is embedded when plugin is active
|
|
828
832
|
swaggerPath: '/swagger', // TODO: Get from swagger plugin config
|
|
829
|
-
liveComponents:
|
|
833
|
+
liveComponents: liveServer?.registry.getRegisteredComponentNames() ?? []
|
|
830
834
|
}
|
|
831
835
|
|
|
832
836
|
// Display banner if enabled
|
package/core/index.ts
CHANGED
|
@@ -24,7 +24,7 @@ export * from './cli/generators'
|
|
|
24
24
|
|
|
25
25
|
// Plugin system (avoid wildcard to prevent conflicts)
|
|
26
26
|
export { PluginRegistry } from './plugins/registry'
|
|
27
|
-
export { PluginDiscovery
|
|
27
|
+
export { PluginDiscovery } from './plugins/discovery'
|
|
28
28
|
export { PluginManager } from './plugins/manager'
|
|
29
29
|
export { PluginUtils } from './plugins'
|
|
30
30
|
|
package/core/plugins/index.ts
CHANGED
|
@@ -34,7 +34,7 @@ export { PluginRegistry } from './registry'
|
|
|
34
34
|
export type { PluginRegistryConfig } from './registry'
|
|
35
35
|
|
|
36
36
|
// Plugin discovery
|
|
37
|
-
export { PluginDiscovery
|
|
37
|
+
export { PluginDiscovery } from './discovery'
|
|
38
38
|
export type { PluginDiscoveryConfig } from './discovery'
|
|
39
39
|
|
|
40
40
|
// Plugin configuration management
|
package/core/plugins/manager.ts
CHANGED
|
@@ -24,6 +24,7 @@ import type { Logger } from "@core/utils/logger"
|
|
|
24
24
|
import { PluginRegistry } from "./registry"
|
|
25
25
|
import { createPluginUtils } from "./config"
|
|
26
26
|
import { FluxStackError } from "@core/utils/errors"
|
|
27
|
+
import { pluginClientHooks } from "@core/server/plugin-client-hooks"
|
|
27
28
|
import { EventEmitter } from "events"
|
|
28
29
|
|
|
29
30
|
/**
|
|
@@ -505,7 +506,10 @@ export class PluginManager extends EventEmitter {
|
|
|
505
506
|
logger: this.logger.child ? this.logger.child({ plugin: plugin.name }) : this.logger,
|
|
506
507
|
app: this.app,
|
|
507
508
|
utils: createPluginUtils(this.logger),
|
|
508
|
-
registry: this.registry
|
|
509
|
+
registry: this.registry,
|
|
510
|
+
clientHooks: {
|
|
511
|
+
register: (hookName: string, jsCode: string) => pluginClientHooks.register(hookName, jsCode)
|
|
512
|
+
}
|
|
509
513
|
}
|
|
510
514
|
|
|
511
515
|
this.contexts.set(plugin.name, context)
|
package/core/plugins/types.ts
CHANGED
|
@@ -33,12 +33,28 @@ export type PluginHook =
|
|
|
33
33
|
|
|
34
34
|
export type PluginPriority = 'highest' | 'high' | 'normal' | 'low' | 'lowest' | number
|
|
35
35
|
|
|
36
|
+
export interface PluginClientHooksAPI {
|
|
37
|
+
/**
|
|
38
|
+
* Register JavaScript code to be executed on the client at a specific hook point.
|
|
39
|
+
*
|
|
40
|
+
* Built-in hook points:
|
|
41
|
+
* - 'onEdenInit' — runs after the Eden Treaty client is created
|
|
42
|
+
* - 'onLiveConnect' — runs when the LiveComponents WebSocket connects
|
|
43
|
+
*
|
|
44
|
+
* @param hookName - The hook point name
|
|
45
|
+
* @param jsCode - JavaScript code string to execute on the client
|
|
46
|
+
*/
|
|
47
|
+
register(hookName: string, jsCode: string): void
|
|
48
|
+
}
|
|
49
|
+
|
|
36
50
|
export interface PluginContext {
|
|
37
51
|
config: FluxStackConfig
|
|
38
52
|
logger: Logger
|
|
39
53
|
app: unknown // Elysia app
|
|
40
54
|
utils: PluginUtils
|
|
41
55
|
registry?: unknown // Plugin registry reference
|
|
56
|
+
/** Register client-side JS hooks that plugins can inject */
|
|
57
|
+
clientHooks: PluginClientHooksAPI
|
|
42
58
|
}
|
|
43
59
|
|
|
44
60
|
export interface PluginUtils {
|
|
@@ -190,7 +206,7 @@ export namespace FluxStack {
|
|
|
190
206
|
* @example
|
|
191
207
|
* // ✅ New way (recommended):
|
|
192
208
|
* // plugins/my-plugin/config/index.ts
|
|
193
|
-
* import { defineConfig, config } from '@
|
|
209
|
+
* import { defineConfig, config } from '@fluxstack/config'
|
|
194
210
|
* export const myConfig = defineConfig({ ... })
|
|
195
211
|
*
|
|
196
212
|
* // ❌ Old way (deprecated):
|
package/core/server/index.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
// FluxStack framework exports
|
|
2
2
|
export { FluxStackFramework } from "../framework/server"
|
|
3
|
-
export { vitePlugin
|
|
3
|
+
export { vitePlugin } from "../plugins/built-in"
|
|
4
4
|
export { swaggerPlugin } from "../plugins/built-in/swagger"
|
|
5
5
|
export { PluginRegistry } from "../plugins/registry"
|
|
6
6
|
export * from "../types"
|
|
7
7
|
|
|
8
8
|
// Live Components exports
|
|
9
|
-
export { liveComponentsPlugin,
|
|
9
|
+
export { liveComponentsPlugin, liveServer, registerAuthProvider } from "./live"
|
|
10
10
|
export { LiveComponent } from "../types/types"
|
|
11
11
|
|
|
12
12
|
// Static Files Plugin
|
|
13
13
|
export { staticFilesPlugin } from "./plugins/static-files-plugin"
|
|
14
14
|
|
|
15
|
+
// Plugin Client Hooks
|
|
16
|
+
export { pluginClientHooks } from "./plugin-client-hooks"
|
|
17
|
+
|
|
15
18
|
export * from "../types/types"
|
|
@@ -24,6 +24,7 @@ export { AuthenticatedContext, AnonymousContext, ANONYMOUS_CONTEXT } from '@flux
|
|
|
24
24
|
export type {
|
|
25
25
|
LiveAuthProvider,
|
|
26
26
|
LiveAuthCredentials,
|
|
27
|
+
LiveAuthSession,
|
|
27
28
|
LiveAuthUser,
|
|
28
29
|
LiveAuthContext,
|
|
29
30
|
LiveComponentAuth,
|
|
@@ -32,78 +33,14 @@ export type {
|
|
|
32
33
|
LiveAuthResult,
|
|
33
34
|
} from '@fluxstack/live'
|
|
34
35
|
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
import { liveServer, pendingAuthProviders } from './websocket-plugin'
|
|
36
|
+
// Register auth provider — buffers if LiveServer not yet initialized
|
|
37
|
+
import { liveServer as _ls, pendingAuthProviders } from './websocket-plugin'
|
|
38
38
|
import type { LiveAuthProvider as _LiveAuthProvider } from '@fluxstack/live'
|
|
39
|
-
import type { ComponentRegistry as _ComponentRegistry } from '@fluxstack/live'
|
|
40
|
-
import type { WebSocketConnectionManager as _WebSocketConnectionManager } from '@fluxstack/live'
|
|
41
|
-
import type { RoomStateManager as _RoomStateManager } from '@fluxstack/live'
|
|
42
|
-
import type { LiveRoomManager as _LiveRoomManager } from '@fluxstack/live'
|
|
43
|
-
import type { RoomEventBus as _RoomEventBus } from '@fluxstack/live'
|
|
44
|
-
import type { FileUploadManager as _FileUploadManager } from '@fluxstack/live'
|
|
45
|
-
import type { PerformanceMonitor as _PerformanceMonitor } from '@fluxstack/live'
|
|
46
|
-
import type { StateSignatureManager as _StateSignatureManager } from '@fluxstack/live'
|
|
47
|
-
import type { LiveAuthManager as _LiveAuthManager } from '@fluxstack/live'
|
|
48
39
|
|
|
49
|
-
function
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
)
|
|
40
|
+
export function registerAuthProvider(provider: _LiveAuthProvider) {
|
|
41
|
+
if (_ls) {
|
|
42
|
+
_ls.useAuth(provider)
|
|
43
|
+
} else {
|
|
44
|
+
pendingAuthProviders.push(provider)
|
|
55
45
|
}
|
|
56
|
-
return liveServer
|
|
57
46
|
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Backward-compatible liveAuthManager.
|
|
61
|
-
* Buffers register() calls that happen before the plugin setup(),
|
|
62
|
-
* then delegates to liveServer.authManager once available.
|
|
63
|
-
* @deprecated Access via liveServer.authManager instead
|
|
64
|
-
*/
|
|
65
|
-
export const liveAuthManager: Pick<_LiveAuthManager, 'authenticate' | 'hasProviders' | 'authorizeRoom' | 'authorizeAction' | 'authorizeComponent'> & { register: (provider: _LiveAuthProvider) => void } = {
|
|
66
|
-
register(provider: _LiveAuthProvider) {
|
|
67
|
-
if (liveServer) {
|
|
68
|
-
liveServer.useAuth(provider)
|
|
69
|
-
} else {
|
|
70
|
-
pendingAuthProviders.push(provider)
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
get authenticate() { return requireLiveServer().authManager.authenticate.bind(requireLiveServer().authManager) },
|
|
74
|
-
get hasProviders() { return requireLiveServer().authManager.hasProviders.bind(requireLiveServer().authManager) },
|
|
75
|
-
get authorizeRoom() { return requireLiveServer().authManager.authorizeRoom.bind(requireLiveServer().authManager) },
|
|
76
|
-
get authorizeAction() { return requireLiveServer().authManager.authorizeAction.bind(requireLiveServer().authManager) },
|
|
77
|
-
get authorizeComponent() { return requireLiveServer().authManager.authorizeComponent.bind(requireLiveServer().authManager) },
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/** Helper to create a typed lazy proxy that delegates to a LiveServer property */
|
|
81
|
-
function createLazyProxy<T extends object>(accessor: () => T): T {
|
|
82
|
-
return new Proxy({} as T, {
|
|
83
|
-
get(_, prop) { return (accessor() as Record<string | symbol, unknown>)[prop] }
|
|
84
|
-
})
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/** @deprecated Access via liveServer.registry instead */
|
|
88
|
-
export const componentRegistry = createLazyProxy<_ComponentRegistry>(() => requireLiveServer().registry)
|
|
89
|
-
|
|
90
|
-
/** @deprecated Access via liveServer.connectionManager instead */
|
|
91
|
-
export const connectionManager = createLazyProxy<_WebSocketConnectionManager>(() => requireLiveServer().connectionManager)
|
|
92
|
-
|
|
93
|
-
/** @deprecated Access via liveServer.roomManager instead */
|
|
94
|
-
export const liveRoomManager = createLazyProxy<_LiveRoomManager>(() => requireLiveServer().roomManager)
|
|
95
|
-
|
|
96
|
-
/** @deprecated Access via liveServer.roomEvents instead */
|
|
97
|
-
export const roomEvents = createLazyProxy<_RoomEventBus>(() => requireLiveServer().roomEvents)
|
|
98
|
-
|
|
99
|
-
/** @deprecated Access via liveServer.fileUploadManager instead */
|
|
100
|
-
export const fileUploadManager = createLazyProxy<_FileUploadManager>(() => requireLiveServer().fileUploadManager)
|
|
101
|
-
|
|
102
|
-
/** @deprecated Access via liveServer.performanceMonitor instead */
|
|
103
|
-
export const performanceMonitor = createLazyProxy<_PerformanceMonitor>(() => requireLiveServer().performanceMonitor)
|
|
104
|
-
|
|
105
|
-
/** @deprecated Access via liveServer.stateSignature instead */
|
|
106
|
-
export const stateSignature = createLazyProxy<_StateSignatureManager>(() => requireLiveServer().stateSignature)
|
|
107
|
-
|
|
108
|
-
// Room state backward compat
|
|
109
|
-
export const roomState = createLazyProxy<_LiveRoomManager>(() => requireLiveServer().roomManager)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Client Hook Registry
|
|
3
|
+
*
|
|
4
|
+
* Singleton registry where server-side plugins register JavaScript code
|
|
5
|
+
* to be executed on the client. The client fetches these hooks via
|
|
6
|
+
* GET /api/__plugins/client-hooks and executes them at the right moment
|
|
7
|
+
* (e.g., when Eden Treaty initializes, when LiveComponents WebSocket connects).
|
|
8
|
+
*
|
|
9
|
+
* Plugins call `pluginClientHooks.register(hookName, jsCode)` during their
|
|
10
|
+
* setup phase to inject client-side behavior.
|
|
11
|
+
*
|
|
12
|
+
* Built-in hook points:
|
|
13
|
+
* - 'onEdenInit' — runs after the Eden Treaty client is created
|
|
14
|
+
* - 'onLiveConnect' — runs when the LiveComponents WebSocket connects
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
class PluginClientHookRegistry {
|
|
18
|
+
private hooks = new Map<string, string[]>()
|
|
19
|
+
private _cachedSignature: string | null = null
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Register a JavaScript code string to be executed on the client
|
|
23
|
+
* for the given hook name.
|
|
24
|
+
*
|
|
25
|
+
* @param hookName - The hook point name (e.g., 'onEdenInit', 'onLiveConnect')
|
|
26
|
+
* @param jsCode - JavaScript code string to execute on the client
|
|
27
|
+
*/
|
|
28
|
+
register(hookName: string, jsCode: string): void {
|
|
29
|
+
const existing = this.hooks.get(hookName)
|
|
30
|
+
if (existing) {
|
|
31
|
+
existing.push(jsCode)
|
|
32
|
+
} else {
|
|
33
|
+
this.hooks.set(hookName, [jsCode])
|
|
34
|
+
}
|
|
35
|
+
this._cachedSignature = null // invalidate on change
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get all registered hooks as a plain object.
|
|
40
|
+
* Used by the HTTP endpoint to serialize the response.
|
|
41
|
+
*/
|
|
42
|
+
getHooks(): Record<string, string[]> {
|
|
43
|
+
const result: Record<string, string[]> = {}
|
|
44
|
+
for (const [name, codes] of this.hooks) {
|
|
45
|
+
result[name] = [...codes]
|
|
46
|
+
}
|
|
47
|
+
return result
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get code strings for a specific hook name.
|
|
52
|
+
*/
|
|
53
|
+
getHook(name: string): string[] {
|
|
54
|
+
return this.hooks.get(name) ? [...this.hooks.get(name)!] : []
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Get HMAC-SHA256 signature of the hooks payload.
|
|
59
|
+
* Uses a per-process secret (random on startup) so the signature
|
|
60
|
+
* is only valid for this server instance.
|
|
61
|
+
*
|
|
62
|
+
* The client receives this signature via WebSocket (CONNECTION_ESTABLISHED)
|
|
63
|
+
* and verifies it against the HTTP response to prevent injection.
|
|
64
|
+
*/
|
|
65
|
+
getSignature(): string {
|
|
66
|
+
if (this._cachedSignature) return this._cachedSignature
|
|
67
|
+
const { createHmac, randomBytes } = require('crypto')
|
|
68
|
+
if (!this._secret) this._secret = randomBytes(32)
|
|
69
|
+
const payload = JSON.stringify(this.getHooks())
|
|
70
|
+
this._cachedSignature = createHmac('sha256', this._secret).update(payload).digest('hex') as string
|
|
71
|
+
return this._cachedSignature!
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** @internal Per-process secret for HMAC signing */
|
|
75
|
+
private _secret: Buffer | null = null
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get hooks + signature for the HTTP response.
|
|
79
|
+
*/
|
|
80
|
+
getSignedResponse(): { hooks: Record<string, string[]>; signature: string } {
|
|
81
|
+
return {
|
|
82
|
+
hooks: this.getHooks(),
|
|
83
|
+
signature: this.getSignature(),
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Clear all registered hooks. Useful for testing.
|
|
89
|
+
*/
|
|
90
|
+
clear(): void {
|
|
91
|
+
this.hooks.clear()
|
|
92
|
+
this._cachedSignature = null
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const pluginClientHooks = new PluginClientHookRegistry()
|
|
97
|
+
export type { PluginClientHookRegistry }
|
package/core/types/types.ts
CHANGED
package/core/utils/version.ts
CHANGED
package/create-fluxstack.ts
CHANGED
|
@@ -418,7 +418,7 @@ FluxStack includes several built-in plugins that are ready to use:
|
|
|
418
418
|
|
|
419
419
|
\`\`\`typescript
|
|
420
420
|
// app/server/index.ts
|
|
421
|
-
import {
|
|
421
|
+
import { swaggerPlugin } from "@core/server"
|
|
422
422
|
|
|
423
423
|
// Add built-in plugins
|
|
424
424
|
app.use(loggerPlugin)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-fluxstack",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.0",
|
|
4
4
|
"description": "⚡ Revolutionary full-stack TypeScript framework with Declarative Config System, Elysia + React + Bun",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -75,12 +75,15 @@
|
|
|
75
75
|
"vitest": "^3.2.4"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@fluxstack/live": "^0.3.1",
|
|
79
|
-
"@fluxstack/live-elysia": "^0.2.1",
|
|
80
|
-
"@fluxstack/live-client": "^0.3.1",
|
|
81
|
-
"@fluxstack/live-react": "^0.3.1",
|
|
82
78
|
"@elysiajs/eden": "^1.3.2",
|
|
83
79
|
"@elysiajs/swagger": "^1.3.1",
|
|
80
|
+
"@fluxstack/config": "^1.0.0",
|
|
81
|
+
"@fluxstack/live": "^0.5.1",
|
|
82
|
+
"@fluxstack/live-client": "^0.5.1",
|
|
83
|
+
"@fluxstack/live-elysia": "^0.5.1",
|
|
84
|
+
"@fluxstack/live-react": "^0.5.1",
|
|
85
|
+
"@fluxstack/plugin-crypto-auth": "^1.0.0",
|
|
86
|
+
"@fluxstack/plugin-csrf-protection": "^1.1.0",
|
|
84
87
|
"@vitejs/plugin-react": "^4.6.0",
|
|
85
88
|
"chalk": "^5.3.0",
|
|
86
89
|
"commander": "^12.1.0",
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type StatusBadgeProps = {
|
|
2
|
+
status: 'online' | 'offline' | 'away'
|
|
3
|
+
size?: 'sm' | 'md' | 'lg'
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export default function StatusBadge({ status, size = 'md' }: StatusBadgeProps) {
|
|
7
|
+
const statusClasses = {
|
|
8
|
+
online: 'bg-green-100 text-green-700',
|
|
9
|
+
offline: 'bg-gray-100 text-gray-700',
|
|
10
|
+
away: 'bg-yellow-100 text-yellow-700',
|
|
11
|
+
}
|
|
12
|
+
const sizeClasses = {
|
|
13
|
+
sm: 'px-2 py-0.5 text-xs',
|
|
14
|
+
md: 'px-2.5 py-1 text-sm',
|
|
15
|
+
lg: 'px-3 py-1.5 text-base',
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<span className={`inline-flex items-center rounded-full font-medium ${statusClasses[status]} ${sizeClasses[size]}`}>
|
|
20
|
+
{status}
|
|
21
|
+
</span>
|
|
22
|
+
)
|
|
23
|
+
}
|