hightjs 0.3.5 → 0.5.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/README.md +48 -116
- package/dist/bin/hightjs.js +51 -23
- package/dist/builder.js +198 -8
- package/dist/client/DefaultNotFound.d.ts +1 -1
- package/dist/client/DefaultNotFound.js +72 -46
- package/dist/client/client.d.ts +3 -0
- package/dist/{client.js → client/client.js} +4 -4
- package/dist/client/entry.client.js +77 -9
- package/dist/global/global.d.ts +117 -0
- package/dist/{auth/types.js → global/global.js} +0 -1
- package/dist/helpers.js +80 -2
- package/dist/hotReload.js +84 -4
- package/dist/index.js +72 -61
- package/dist/loaders.d.ts +1 -0
- package/dist/loaders.js +46 -0
- package/dist/renderer.js +158 -4
- package/dist/types.d.ts +44 -0
- package/package.json +37 -30
- package/.idea/HightJS.iml +0 -9
- package/.idea/copilot.data.migration.agent.xml +0 -6
- package/.idea/copilot.data.migration.ask.xml +0 -6
- package/.idea/copilot.data.migration.ask2agent.xml +0 -6
- package/.idea/copilot.data.migration.edit.xml +0 -6
- package/.idea/copilotDiffState.xml +0 -67
- package/.idea/inspectionProfiles/Project_Default.xml +0 -13
- package/.idea/libraries/test_package.xml +0 -9
- package/.idea/libraries/ts_commonjs_default_export.xml +0 -9
- package/.idea/misc.xml +0 -7
- package/.idea/modules.xml +0 -8
- package/.idea/vcs.xml +0 -6
- package/dist/auth/client.d.ts +0 -24
- package/dist/auth/client.js +0 -146
- package/dist/auth/components.d.ts +0 -29
- package/dist/auth/components.js +0 -100
- package/dist/auth/core.d.ts +0 -55
- package/dist/auth/core.js +0 -189
- package/dist/auth/index.d.ts +0 -7
- package/dist/auth/index.js +0 -45
- package/dist/auth/jwt.d.ts +0 -41
- package/dist/auth/jwt.js +0 -185
- package/dist/auth/providers/credentials.d.ts +0 -60
- package/dist/auth/providers/credentials.js +0 -97
- package/dist/auth/providers/discord.d.ts +0 -63
- package/dist/auth/providers/discord.js +0 -190
- package/dist/auth/providers/google.d.ts +0 -63
- package/dist/auth/providers/google.js +0 -186
- package/dist/auth/providers/index.d.ts +0 -2
- package/dist/auth/providers/index.js +0 -35
- package/dist/auth/providers.d.ts +0 -3
- package/dist/auth/providers.js +0 -26
- package/dist/auth/react/index.d.ts +0 -6
- package/dist/auth/react/index.js +0 -48
- package/dist/auth/react.d.ts +0 -22
- package/dist/auth/react.js +0 -199
- package/dist/auth/routes.d.ts +0 -16
- package/dist/auth/routes.js +0 -152
- package/dist/auth/types.d.ts +0 -76
- package/dist/client.d.ts +0 -3
- package/docs/README.md +0 -58
- package/docs/arquivos-especiais.md +0 -10
- package/docs/autenticacao.md +0 -212
- package/docs/checklist.md +0 -9
- package/docs/cli.md +0 -72
- package/docs/config.md +0 -216
- package/docs/estrutura.md +0 -20
- package/docs/faq.md +0 -10
- package/docs/hot-reload.md +0 -5
- package/docs/integracoes.md +0 -240
- package/docs/middlewares.md +0 -73
- package/docs/rotas-backend.md +0 -45
- package/docs/rotas-frontend.md +0 -66
- package/docs/seguranca.md +0 -8
- package/docs/websocket.md +0 -45
- package/example/certs/cert.pem +0 -20
- package/example/certs/key.pem +0 -27
- package/example/hightjs.config.ts +0 -87
- package/example/package-lock.json +0 -1174
- package/example/package.json +0 -26
- package/example/postcss.config.js +0 -8
- package/example/src/auth.ts +0 -42
- package/example/src/web/backend/routes/auth.ts +0 -3
- package/example/src/web/backend/routes/version.ts +0 -13
- package/example/src/web/globals.css +0 -5
- package/example/src/web/layout.tsx +0 -100
- package/example/src/web/routes/index.tsx +0 -153
- package/example/src/web/routes/login.tsx +0 -175
- package/example/tailwind.config.js +0 -12
- package/example/tsconfig.json +0 -15
- package/src/adapters/express.ts +0 -87
- package/src/adapters/factory.ts +0 -112
- package/src/adapters/fastify.ts +0 -104
- package/src/adapters/native.ts +0 -234
- package/src/api/console.ts +0 -305
- package/src/api/http.ts +0 -535
- package/src/auth/client.ts +0 -171
- package/src/auth/components.tsx +0 -125
- package/src/auth/core.ts +0 -215
- package/src/auth/index.ts +0 -25
- package/src/auth/jwt.ts +0 -210
- package/src/auth/providers/credentials.ts +0 -139
- package/src/auth/providers/discord.ts +0 -239
- package/src/auth/providers/google.ts +0 -234
- package/src/auth/providers/index.ts +0 -20
- package/src/auth/providers.ts +0 -20
- package/src/auth/react/index.ts +0 -25
- package/src/auth/react.tsx +0 -234
- package/src/auth/routes.ts +0 -183
- package/src/auth/types.ts +0 -108
- package/src/bin/hightjs.js +0 -222
- package/src/builder.js +0 -411
- package/src/client/DefaultNotFound.tsx +0 -84
- package/src/client/clientRouter.ts +0 -153
- package/src/client/entry.client.tsx +0 -444
- package/src/client.ts +0 -24
- package/src/components/Link.tsx +0 -38
- package/src/helpers.ts +0 -542
- package/src/hotReload.ts +0 -489
- package/src/index.ts +0 -546
- package/src/renderer.tsx +0 -263
- package/src/router.ts +0 -730
- package/src/types/framework.ts +0 -58
- package/src/types.ts +0 -207
- package/tsconfig.json +0 -17
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="CopilotDiffPersistence">
|
|
4
|
-
<option name="pendingDiffs">
|
|
5
|
-
<map>
|
|
6
|
-
<entry key="$PROJECT_DIR$/src/types/websocket.ts">
|
|
7
|
-
<value>
|
|
8
|
-
<PendingDiffInfo>
|
|
9
|
-
<option name="filePath" value="$PROJECT_DIR$/src/types/websocket.ts" />
|
|
10
|
-
<option name="updatedContent" value="import { IncomingMessage } from 'http'; import { WebSocket } from 'ws'; export interface WebSocketContext { ws: WebSocket; req: IncomingMessage; url: URL; params: Record<string, string>; query: Record<string, string>; send: (data: any) => void; close: (code?: number, reason?: string) => void; broadcast: (data: any, exclude?: WebSocket[]) => void; } export interface WebSocketHandler { (ctx: WebSocketContext): void | Promise<void>; } export interface WebSocketRoute { path: string; handler: WebSocketHandler; pathPattern?: RegExp; paramNames?: string[]; } export interface WebSocketServer { route: (path: string, handler: WebSocketHandler) => void; start: (port?: number) => void; broadcast: (data: any) => void; getConnections: () => WebSocket[]; }" />
|
|
11
|
-
</PendingDiffInfo>
|
|
12
|
-
</value>
|
|
13
|
-
</entry>
|
|
14
|
-
<entry key="$PROJECT_DIR$/src/websocket/adapter.ts">
|
|
15
|
-
<value>
|
|
16
|
-
<PendingDiffInfo>
|
|
17
|
-
<option name="filePath" value="$PROJECT_DIR$/src/websocket/adapter.ts" />
|
|
18
|
-
<option name="updatedContent" value="import { Server } from 'http'; import { WebSocketServer as WSServer } from 'ws'; import { HightWSServer } from './server'; import { WebSocketServer, WebSocketHandler } from '../types/websocket'; import Console, { Colors } from '../api/console'; export class WebSocketAdapter { private wsServer: HightWSServer; private httpServer: Server | null = null; private wss: WSServer | null = null; constructor() { this.wsServer = new HightWSServer(); } /** * Integra WebSocket com um servidor HTTP existente */ attachToHttpServer(httpServer: Server): void { this.httpServer = httpServer; this.wss = new WSServer({ server: httpServer, perMessageDeflate: false }); console.log(`${Colors.FgGreen}✓${Colors.Reset} WebSocket attached to HTTP server`); this.wss.on('connection', (ws, req) => { this.wsServer['handleConnection'](ws, req); }); this.wss.on('error', (error) => { console.error(`${Colors.FgRed}[WebSocket Server Error]${Colors.Reset}`, error); }); } /** * Adiciona uma rota WebSocket */ route(path: string, handler: WebSocketHandler): void { this.wsServer.route(path, handler); } /** * Faz broadcast para todas as conexões */ broadcast(data: any): void { this.wsServer.broadcast(data); } /** * Retorna todas as conexões ativas */ getConnections() { return this.wsServer.getConnections(); } /** * Inicia servidor WebSocket standalone */ startStandalone(port: number = 8080): void { this.wsServer.start(port); } }" />
|
|
19
|
-
</PendingDiffInfo>
|
|
20
|
-
</value>
|
|
21
|
-
</entry>
|
|
22
|
-
<entry key="$PROJECT_DIR$/src/websocket/client.ts">
|
|
23
|
-
<value>
|
|
24
|
-
<PendingDiffInfo>
|
|
25
|
-
<option name="filePath" value="$PROJECT_DIR$/src/websocket/client.ts" />
|
|
26
|
-
<option name="originalContent" value=" " />
|
|
27
|
-
<option name="updatedContent" value="import React from 'react'; export class HightWSClient { private ws: WebSocket | null = null; private url: string; private reconnectAttempts: number = 0; private maxReconnectAttempts: number = 5; private reconnectDelay: number = 1000; private listeners: Map<string, Function[]> = new Map(); constructor(url: string) { this.url = url; this.connect(); } private connect(): void { try { this.ws = new WebSocket(this.url); this.ws.onopen = (event) => { console.log('[HightWS] Connected to WebSocket server'); this.reconnectAttempts = 0; this.emit('open', event); }; this.ws.onmessage = (event) => { try { const data = JSON.parse(event.data); this.emit('message', data); } catch (error) { // Se não for JSON, envia como string this.emit('message', event.data); } }; this.ws.onclose = (event) => { console.log('[HightWS] Connection closed'); this.emit('close', event); this.attemptReconnect(); }; this.ws.onerror = (event) => { console.error('[HightWS] WebSocket error:', event); this.emit('error', event); }; } catch (error) { console.error('[HightWS] Failed to connect:', error); this.attemptReconnect(); } } private attemptReconnect(): void { if (this.reconnectAttempts < this.maxReconnectAttempts) { this.reconnectAttempts++; console.log(`[HightWS] Attempting to reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`); setTimeout(() => { this.connect(); }, this.reconnectDelay * this.reconnectAttempts); } else { console.error('[HightWS] Max reconnection attempts reached'); this.emit('maxReconnectAttemptsReached'); } } public send(data: any): void { if (this.ws && this.ws.readyState === WebSocket.OPEN) { const message = typeof data === 'string' ? data : JSON.stringify(data); this.ws.send(message); } else { console.warn('[HightWS] WebSocket is not connected'); } } public on(event: string, callback: Function): void { if (!this.listeners.has(event)) { this.listeners.set(event, []); } this.listeners.get(event)!.push(callback); } public off(event: string, callback?: Function): void { if (!this.listeners.has(event)) return; if (callback) { const callbacks = this.listeners.get(event)!; const index = callbacks.indexOf(callback); if (index > -1) { callbacks.splice(index, 1); } } else { this.listeners.delete(event); } } private emit(event: string, data?: any): void { if (this.listeners.has(event)) { this.listeners.get(event)!.forEach(callback => { try { callback(data); } catch (error) { console.error(`[HightWS] Error in event listener for ${event}:`, error); } }); } } public close(): void { if (this.ws) { this.ws.close(); this.ws = null; } } public get readyState(): number { return this.ws ? this.ws.readyState : WebSocket.CLOSED; } public get isConnected(): boolean { return this.ws !== null && this.ws.readyState === WebSocket.OPEN; } } // Hook React para usar WebSocket export function useWebSocket(url: string) { const [client, setClient] = React.useState<HightWSClient | null>(null); const [isConnected, setIsConnected] = React.useState(false); const [lastMessage, setLastMessage] = React.useState<any>(null); React.useEffect(() => { const wsClient = new HightWSClient(url); wsClient.on('open', () => { setIsConnected(true); }); wsClient.on('close', () => { setIsConnected(false); }); wsClient.on('message', (data) => { setLastMessage(data); }); setClient(wsClient); return () => { wsClient.close(); }; }, [url]); const sendMessage = React.useCallback((data: any) => { if (client) { client.send(data); } }, [client]); return { client, isConnected, lastMessage, sendMessage }; }" />
|
|
28
|
-
</PendingDiffInfo>
|
|
29
|
-
</value>
|
|
30
|
-
</entry>
|
|
31
|
-
<entry key="$PROJECT_DIR$/src/websocket/example.ts">
|
|
32
|
-
<value>
|
|
33
|
-
<PendingDiffInfo>
|
|
34
|
-
<option name="filePath" value="$PROJECT_DIR$/src/websocket/example.ts" />
|
|
35
|
-
<option name="updatedContent" value="// Exemplo de uso do WebSocket no HightJS // ============================================ // BACKEND - Como criar rotas WebSocket // ============================================ // Em src/web/backend/websocket.ts (ou qualquer arquivo backend) import { ws } from 'hightjs/ws'; // Rota simples de chat ws('/chat', (ctx) => { console.log('Nova conexão no chat:', ctx.req.socket.remoteAddress); // Envia mensagem de boas-vindas ctx.send({ type: 'welcome', message: 'Bem-vindo ao chat!' }); // Escuta mensagens do cliente ctx.ws.on('message', (data) => { try { const message = JSON.parse(data.toString()); // Faz broadcast da mensagem para todos os outros clientes ctx.broadcast({ type: 'message', user: message.user || 'Anônimo', text: message.text, timestamp: new Date().toISOString() }, [ctx.ws]); // Exclui o remetente } catch (error) { console.error('Erro ao processar mensagem:', error); } }); // Quando a conexão fechar ctx.ws.on('close', () => { console.log('Cliente desconectado do chat'); }); }); // Rota com parâmetros ws('/room/:roomId', (ctx) => { const { roomId } = ctx.params; console.log(`Nova conexão na sala: ${roomId}`); ctx.send({ type: 'joined', room: roomId, message: `Você entrou na sala ${roomId}` }); }); // Rota para notificações em tempo real ws('/notifications/:userId', (ctx) => { const { userId } = ctx.params; // Pode usar query params também const token = ctx.query.token; if (!token) { ctx.close(1008, 'Token obrigatório'); return; } console.log(`Usuário ${userId} conectado para notificações`); // Simula envio de notificação a cada 30 segundos const interval = setInterval(() => { ctx.send({ type: 'notification', title: 'Nova notificação', body: 'Você tem uma nova mensagem', timestamp: new Date().toISOString() }); }, 30000); ctx.ws.on('close', () => { clearInterval(interval); console.log(`Usuário ${userId} desconectado das notificações`); }); }); // ============================================ // FRONTEND - Como usar WebSocket no React // ============================================ // Em qualquer componente React import React from 'react'; import { HightWSClient, useWebSocket } from 'hightjs/ws'; // Método 1: Usando o hook useWebSocket (mais fácil) function ChatComponent() { const { client, isConnected, lastMessage, sendMessage } = useWebSocket('ws://localhost:8080/chat'); const [messages, setMessages] = React.useState([]); const [newMessage, setNewMessage] = React.useState(''); // Atualiza mensagens quando recebe uma nova React.useEffect(() => { if (lastMessage && lastMessage.type === 'message') { setMessages(prev => [...prev, lastMessage]); } }, [lastMessage]); const handleSendMessage = () => { if (newMessage.trim() && isConnected) { sendMessage({ user: 'Seu Nome', text: newMessage }); setNewMessage(''); } }; return ( <div> <div>Status: {isConnected ? 'Conectado' : 'Desconectado'}</div> <div style={{ height: '300px', overflow: 'auto', border: '1px solid #ccc' }}> {messages.map((msg, index) => ( <div key={index}> <strong>{msg.user}:</strong> {msg.text} <small> ({new Date(msg.timestamp).toLocaleTimeString()})</small> </div> ))} </div> <div> <input value={newMessage} onChange={(e) => setNewMessage(e.target.value)} onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()} placeholder="Digite sua mensagem..." /> <button onClick={handleSendMessage} disabled={!isConnected}> Enviar </button> </div> </div> ); } // Método 2: Usando a classe HightWSClient diretamente (mais controle) function NotificationsComponent() { const [client, setClient] = React.useState(null); const [notifications, setNotifications] = React.useState([]); const userId = '123'; // ID do usuário atual React.useEffect(() => { const wsClient = new HightWSClient(`ws://localhost:8080/notifications/${userId}?token=abc123`); wsClient.on('open', () => { console.log('Conectado às notificações'); }); wsClient.on('message', (data) => { if (data.type === 'notification') { setNotifications(prev => [data, ...prev.slice(0, 9)]); // Mantém só as 10 últimas // Pode mostrar notificação do browser também if (Notification.permission === 'granted') { new Notification(data.title, { body: data.body }); } } }); wsClient.on('close', () => { console.log('Desconectado das notificações'); }); setClient(wsClient); return () => { wsClient.close(); }; }, [userId]); return ( <div> <h3>Notificações em tempo real</h3> {notifications.map((notif, index) => ( <div key={index} style={{ padding: '10px', border: '1px solid #ddd', margin: '5px 0' }}> <strong>{notif.title}</strong> <p>{notif.body}</p> <small>{new Date(notif.timestamp).toLocaleString()}</small> </div> ))} </div> ); } // ============================================ // INICIANDO O SERVIDOR WEBSOCKET // ============================================ // No seu arquivo principal de servidor (onde você inicia o HightJS) import { createWebSocketServer } from 'hightjs/ws'; // Método 1: Servidor WebSocket independente const wsServer = createWebSocketServer(); wsServer.start(8080); // Inicia na porta 8080 // Método 2: Integrar com servidor HTTP existente (Express/Fastify) // Isso ainda precisa ser implementado nos adapters, mas a estrutura está pronta export default ChatComponent;" />
|
|
36
|
-
</PendingDiffInfo>
|
|
37
|
-
</value>
|
|
38
|
-
</entry>
|
|
39
|
-
<entry key="$PROJECT_DIR$/src/websocket/factory.ts">
|
|
40
|
-
<value>
|
|
41
|
-
<PendingDiffInfo>
|
|
42
|
-
<option name="filePath" value="$PROJECT_DIR$/src/websocket/factory.ts" />
|
|
43
|
-
<option name="updatedContent" value="import { HightWSServer } from './server'; import { WebSocketServer } from '../types/websocket'; /** * Cria uma nova instância do servidor WebSocket HightJS * @returns Uma nova instância do servidor WebSocket */ export function createWebSocketServer(): WebSocketServer { return new HightWSServer(); } /** * Instância global do servidor WebSocket (singleton) */ let globalWSServer: WebSocketServer | null = null; /** * Retorna a instância global do servidor WebSocket ou cria uma nova * @returns A instância global do servidor WebSocket */ export function getGlobalWebSocketServer(): WebSocketServer { if (!globalWSServer) { globalWSServer = new HightWSServer(); } return globalWSServer; } /** * Helper para criar rotas WebSocket rapidamente * @param path Caminho da rota * @param handler Função handler da rota */ export function ws(path: string, handler: (ctx: any) => void | Promise<void>) { const server = getGlobalWebSocketServer(); server.route(path, handler); return server; }" />
|
|
44
|
-
</PendingDiffInfo>
|
|
45
|
-
</value>
|
|
46
|
-
</entry>
|
|
47
|
-
<entry key="$PROJECT_DIR$/src/websocket/index.ts">
|
|
48
|
-
<value>
|
|
49
|
-
<PendingDiffInfo>
|
|
50
|
-
<option name="filePath" value="$PROJECT_DIR$/src/websocket/index.ts" />
|
|
51
|
-
<option name="originalContent" value=" " />
|
|
52
|
-
<option name="updatedContent" value="export { HightWSServer } from './server'; export { WebSocketContext, WebSocketHandler, WebSocketRoute, WebSocketServer } from '../types/websocket'; export { createWebSocketServer } from './factory'; export { HightWSClient, useWebSocket } from './client';" />
|
|
53
|
-
</PendingDiffInfo>
|
|
54
|
-
</value>
|
|
55
|
-
</entry>
|
|
56
|
-
<entry key="$PROJECT_DIR$/src/websocket/server.ts">
|
|
57
|
-
<value>
|
|
58
|
-
<PendingDiffInfo>
|
|
59
|
-
<option name="filePath" value="$PROJECT_DIR$/src/websocket/server.ts" />
|
|
60
|
-
<option name="updatedContent" value="import { WebSocket, WebSocketServer as WSServer } from 'ws'; import { IncomingMessage } from 'http'; import { URL } from 'url'; import { WebSocketContext, WebSocketHandler, WebSocketRoute, WebSocketServer } from '../types/websocket'; import Console, { Colors } from '../api/console'; export class HightWSServer implements WebSocketServer { private wss: WSServer | null = null; private routes: WebSocketRoute[] = []; private connections: Set<WebSocket> = new Set(); constructor() { this.setupRoutePatterns(); } route(path: string, handler: WebSocketHandler): void { const route: WebSocketRoute = { path, handler, ...this.createPathPattern(path) }; this.routes.push(route); console.log(`${Colors.FgBlue}[WebSocket]${Colors.Reset} Route registered: ${Colors.FgYellow}${path}${Colors.Reset}`); } start(port: number = 8080): void { this.wss = new WSServer({ port, perMessageDeflate: false }); console.log(`${Colors.FgGreen}✓${Colors.Reset} WebSocket server listening on port ${Colors.FgYellow}${port}${Colors.Reset}`); this.wss.on('connection', (ws: WebSocket, req: IncomingMessage) => { this.connections.add(ws); console.log(`${Colors.FgBlue}[WebSocket]${Colors.Reset} New connection from ${req.socket.remoteAddress}`); ws.on('close', () => { this.connections.delete(ws); console.log(`${Colors.FgBlue}[WebSocket]${Colors.Reset} Connection closed`); }); ws.on('error', (error) => { console.error(`${Colors.FgRed}[WebSocket Error]${Colors.Reset}`, error); this.connections.delete(ws); }); this.handleConnection(ws, req); }); this.wss.on('error', (error) => { console.error(`${Colors.FgRed}[WebSocket Server Error]${Colors.Reset}`, error); }); } broadcast(data: any): void { const message = typeof data === 'string' ? data : JSON.stringify(data); this.connections.forEach(ws => { if (ws.readyState === WebSocket.OPEN) { ws.send(message); } }); } getConnections(): WebSocket[] { return Array.from(this.connections); } private handleConnection(ws: WebSocket, req: IncomingMessage): void { if (!req.url) return; const url = new URL(req.url, `http://${req.headers.host}`); const pathname = url.pathname; // Encontra a rota correspondente const matchedRoute = this.findMatchingRoute(pathname); if (!matchedRoute) { console.log(`${Colors.FgYellow}[WebSocket]${Colors.Reset} No route found for ${pathname}`); ws.close(1000, 'No route found'); return; } // Extrai parâmetros da URL const params = this.extractParams(pathname, matchedRoute); const query = Object.fromEntries(url.searchParams.entries()); // Cria o contexto const context: WebSocketContext = { ws, req, url, params, query, send: (data: any) => { if (ws.readyState === WebSocket.OPEN) { const message = typeof data === 'string' ? data : JSON.stringify(data); ws.send(message); } }, close: (code?: number, reason?: string) => { ws.close(code || 1000, reason); }, broadcast: (data: any, exclude?: WebSocket[]) => { const message = typeof data === 'string' ? data : JSON.stringify(data); const excludeSet = new Set(exclude || []); this.connections.forEach(connection => { if (connection.readyState === WebSocket.OPEN && !excludeSet.has(connection)) { connection.send(message); } }); } }; try { matchedRoute.handler(context); } catch (error) { console.error(`${Colors.FgRed}[WebSocket Handler Error]${Colors.Reset}`, error); ws.close(1011, 'Internal server error'); } } private createPathPattern(path: string): { pathPattern: RegExp; paramNames: string[] } { const paramNames: string[] = []; const pattern = path .replace(/\//g, '\\/') .replace(/:([^\/]+)/g, (_, paramName) => { paramNames.push(paramName); return '([^/]+)'; }) .replace(/\*/g, '.*'); return { pathPattern: new RegExp(`^${pattern}$`), paramNames }; } private findMatchingRoute(pathname: string): WebSocketRoute | null { return this.routes.find(route => { if (route.pathPattern) { return route.pathPattern.test(pathname); } return route.path === pathname; }) || null; } private extractParams(pathname: string, route: WebSocketRoute): Record<string, string> { const params: Record<string, string> = {}; if (route.pathPattern && route.paramNames) { const match = pathname.match(route.pathPattern); if (match) { route.paramNames.forEach((paramName, index) => { params[paramName] = match[index + 1]; }); } } return params; } private setupRoutePatterns(): void { // Reprocessa todos os patterns das rotas existentes this.routes.forEach(route => { const { pathPattern, paramNames } = this.createPathPattern(route.path); route.pathPattern = pathPattern; route.paramNames = paramNames; }); } }" />
|
|
61
|
-
</PendingDiffInfo>
|
|
62
|
-
</value>
|
|
63
|
-
</entry>
|
|
64
|
-
</map>
|
|
65
|
-
</option>
|
|
66
|
-
</component>
|
|
67
|
-
</project>
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
<component name="InspectionProjectProfileManager">
|
|
2
|
-
<profile version="1.0">
|
|
3
|
-
<option name="myName" value="Project Default" />
|
|
4
|
-
<inspection_tool class="D" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
|
5
|
-
<inspection_tool class="IncorrectHttpHeaderInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
|
6
|
-
<option name="customHeaders">
|
|
7
|
-
<set>
|
|
8
|
-
<option value="Authorization Bearer {{TOKEN}}" />
|
|
9
|
-
</set>
|
|
10
|
-
</option>
|
|
11
|
-
</inspection_tool>
|
|
12
|
-
</profile>
|
|
13
|
-
</component>
|
package/.idea/misc.xml
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="KubernetesApiProvider"><![CDATA[{}]]></component>
|
|
4
|
-
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="ms-21" project-jdk-type="JavaSDK">
|
|
5
|
-
<output url="file://$PROJECT_DIR$/out" />
|
|
6
|
-
</component>
|
|
7
|
-
</project>
|
package/.idea/modules.xml
DELETED
package/.idea/vcs.xml
DELETED
package/dist/auth/client.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { SignInOptions, SignInResult, Session } from './types';
|
|
2
|
-
export declare function setBasePath(path: string): void;
|
|
3
|
-
/**
|
|
4
|
-
* Função para obter a sessão atual (similar ao NextAuth getSession)
|
|
5
|
-
*/
|
|
6
|
-
export declare function getSession(): Promise<Session | null>;
|
|
7
|
-
/**
|
|
8
|
-
* Função para obter token CSRF
|
|
9
|
-
*/
|
|
10
|
-
export declare function getCsrfToken(): Promise<string | null>;
|
|
11
|
-
/**
|
|
12
|
-
* Função para obter providers disponíveis
|
|
13
|
-
*/
|
|
14
|
-
export declare function getProviders(): Promise<any[] | null>;
|
|
15
|
-
/**
|
|
16
|
-
* Função para fazer login (similar ao NextAuth signIn)
|
|
17
|
-
*/
|
|
18
|
-
export declare function signIn(provider?: string, options?: SignInOptions): Promise<SignInResult | undefined>;
|
|
19
|
-
/**
|
|
20
|
-
* Função para fazer logout (similar ao NextAuth signOut)
|
|
21
|
-
*/
|
|
22
|
-
export declare function signOut(options?: {
|
|
23
|
-
callbackUrl?: string;
|
|
24
|
-
}): Promise<void>;
|
package/dist/auth/client.js
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.setBasePath = setBasePath;
|
|
4
|
-
exports.getSession = getSession;
|
|
5
|
-
exports.getCsrfToken = getCsrfToken;
|
|
6
|
-
exports.getProviders = getProviders;
|
|
7
|
-
exports.signIn = signIn;
|
|
8
|
-
exports.signOut = signOut;
|
|
9
|
-
// Configuração global do client
|
|
10
|
-
let basePath = '/api/auth';
|
|
11
|
-
function setBasePath(path) {
|
|
12
|
-
basePath = path;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Função para obter a sessão atual (similar ao NextAuth getSession)
|
|
16
|
-
*/
|
|
17
|
-
async function getSession() {
|
|
18
|
-
try {
|
|
19
|
-
const response = await fetch(`${basePath}/session`, {
|
|
20
|
-
credentials: 'include'
|
|
21
|
-
});
|
|
22
|
-
if (!response.ok) {
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
const data = await response.json();
|
|
26
|
-
return data.session || null;
|
|
27
|
-
}
|
|
28
|
-
catch (error) {
|
|
29
|
-
console.error('[hweb-auth] Error fetching session:', error);
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Função para obter token CSRF
|
|
35
|
-
*/
|
|
36
|
-
async function getCsrfToken() {
|
|
37
|
-
try {
|
|
38
|
-
const response = await fetch(`${basePath}/csrf`, {
|
|
39
|
-
credentials: 'include'
|
|
40
|
-
});
|
|
41
|
-
if (!response.ok) {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
const data = await response.json();
|
|
45
|
-
return data.csrfToken || null;
|
|
46
|
-
}
|
|
47
|
-
catch (error) {
|
|
48
|
-
console.error('[hweb-auth] Error fetching CSRF token:', error);
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Função para obter providers disponíveis
|
|
54
|
-
*/
|
|
55
|
-
async function getProviders() {
|
|
56
|
-
try {
|
|
57
|
-
const response = await fetch(`${basePath}/providers`, {
|
|
58
|
-
credentials: 'include'
|
|
59
|
-
});
|
|
60
|
-
if (!response.ok) {
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
const data = await response.json();
|
|
64
|
-
return data.providers || [];
|
|
65
|
-
}
|
|
66
|
-
catch (error) {
|
|
67
|
-
console.error('[hweb-auth] Error searching for providers:', error);
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Função para fazer login (similar ao NextAuth signIn)
|
|
73
|
-
*/
|
|
74
|
-
async function signIn(provider = 'credentials', options = {}) {
|
|
75
|
-
try {
|
|
76
|
-
const { redirect = true, callbackUrl, ...credentials } = options;
|
|
77
|
-
const response = await fetch(`${basePath}/signin`, {
|
|
78
|
-
method: 'POST',
|
|
79
|
-
headers: {
|
|
80
|
-
'Content-Type': 'application/json',
|
|
81
|
-
},
|
|
82
|
-
credentials: 'include',
|
|
83
|
-
body: JSON.stringify({
|
|
84
|
-
provider,
|
|
85
|
-
...credentials
|
|
86
|
-
})
|
|
87
|
-
});
|
|
88
|
-
const data = await response.json();
|
|
89
|
-
if (response.ok && data.success) {
|
|
90
|
-
// Se é OAuth, redireciona para URL fornecida
|
|
91
|
-
if (data.type === 'oauth' && data.redirectUrl) {
|
|
92
|
-
if (redirect && typeof window !== 'undefined') {
|
|
93
|
-
window.location.href = data.redirectUrl;
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
ok: true,
|
|
97
|
-
status: 200,
|
|
98
|
-
url: data.redirectUrl
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
// Se é sessão (credentials), redireciona para callbackUrl
|
|
102
|
-
if (data.type === 'session') {
|
|
103
|
-
if (redirect && typeof window !== 'undefined') {
|
|
104
|
-
window.location.href = callbackUrl || '/';
|
|
105
|
-
}
|
|
106
|
-
return {
|
|
107
|
-
ok: true,
|
|
108
|
-
status: 200,
|
|
109
|
-
url: callbackUrl || '/'
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
return {
|
|
115
|
-
error: data.error || 'Authentication failed',
|
|
116
|
-
status: response.status,
|
|
117
|
-
ok: false
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
catch (error) {
|
|
122
|
-
console.error('[hweb-auth] Error on signIn:', error);
|
|
123
|
-
return {
|
|
124
|
-
error: 'Network error',
|
|
125
|
-
status: 500,
|
|
126
|
-
ok: false
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Função para fazer logout (similar ao NextAuth signOut)
|
|
132
|
-
*/
|
|
133
|
-
async function signOut(options = {}) {
|
|
134
|
-
try {
|
|
135
|
-
await fetch(`${basePath}/signout`, {
|
|
136
|
-
method: 'POST',
|
|
137
|
-
credentials: 'include'
|
|
138
|
-
});
|
|
139
|
-
if (typeof window !== 'undefined') {
|
|
140
|
-
window.location.href = options.callbackUrl || '/';
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
catch (error) {
|
|
144
|
-
console.error('[hweb-auth] Error on signOut:', error);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import React, { ReactNode } from 'react';
|
|
2
|
-
interface ProtectedRouteProps {
|
|
3
|
-
children: ReactNode;
|
|
4
|
-
fallback?: ReactNode;
|
|
5
|
-
redirectTo?: string;
|
|
6
|
-
requireAuth?: boolean;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Componente para proteger rotas que requerem autenticação
|
|
10
|
-
*/
|
|
11
|
-
export declare function ProtectedRoute({ children, fallback, redirectTo, requireAuth }: ProtectedRouteProps): string | number | bigint | true | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element | null;
|
|
12
|
-
interface GuardProps {
|
|
13
|
-
children: ReactNode;
|
|
14
|
-
fallback?: ReactNode;
|
|
15
|
-
redirectTo?: string;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Guard simples que só renderiza children se estiver autenticado
|
|
19
|
-
*/
|
|
20
|
-
export declare function AuthGuard({ children, fallback, redirectTo }: GuardProps): string | number | bigint | true | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element | null;
|
|
21
|
-
/**
|
|
22
|
-
* Componente para mostrar conteúdo apenas para usuários não autenticados
|
|
23
|
-
*/
|
|
24
|
-
export declare function GuestOnly({ children, fallback, redirectTo }: GuardProps): string | number | bigint | true | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element;
|
|
25
|
-
/**
|
|
26
|
-
* Hook para redirecionar baseado no status de autenticação
|
|
27
|
-
*/
|
|
28
|
-
export declare function useAuthRedirect(authenticatedRedirect?: string, unauthenticatedRedirect?: string): void;
|
|
29
|
-
export {};
|
package/dist/auth/components.js
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.ProtectedRoute = ProtectedRoute;
|
|
7
|
-
exports.AuthGuard = AuthGuard;
|
|
8
|
-
exports.GuestOnly = GuestOnly;
|
|
9
|
-
exports.useAuthRedirect = useAuthRedirect;
|
|
10
|
-
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
11
|
-
/*
|
|
12
|
-
* This file is part of the HightJS Project.
|
|
13
|
-
* Copyright (c) 2025 itsmuzin
|
|
14
|
-
*
|
|
15
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
16
|
-
* you may not use this file except in compliance with the License.
|
|
17
|
-
* You may obtain a copy of the License at
|
|
18
|
-
*
|
|
19
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
20
|
-
*
|
|
21
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
22
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
23
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
24
|
-
* See the License for the specific language governing permissions and
|
|
25
|
-
* limitations under the License.
|
|
26
|
-
*/
|
|
27
|
-
const react_1 = __importDefault(require("react"));
|
|
28
|
-
const react_2 = require("./react");
|
|
29
|
-
const clientRouter_1 = require("../client/clientRouter");
|
|
30
|
-
/**
|
|
31
|
-
* Componente para proteger rotas que requerem autenticação
|
|
32
|
-
*/
|
|
33
|
-
function ProtectedRoute({ children, fallback, redirectTo = '/auth/signin', requireAuth = true }) {
|
|
34
|
-
const { isAuthenticated, isLoading } = (0, react_2.useAuth)();
|
|
35
|
-
// Ainda carregando
|
|
36
|
-
if (isLoading) {
|
|
37
|
-
return fallback || (0, jsx_runtime_1.jsx)("div", { children: "Loading..." });
|
|
38
|
-
}
|
|
39
|
-
// Requer auth mas não está autenticado
|
|
40
|
-
if (requireAuth && !isAuthenticated) {
|
|
41
|
-
if (typeof window !== 'undefined' && redirectTo) {
|
|
42
|
-
window.location.href = redirectTo;
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
return fallback || (0, jsx_runtime_1.jsx)("div", { children: "Unauthorized" });
|
|
46
|
-
}
|
|
47
|
-
// Não requer auth mas está autenticado (ex: página de login)
|
|
48
|
-
if (!requireAuth && isAuthenticated && redirectTo) {
|
|
49
|
-
if (typeof window !== 'undefined') {
|
|
50
|
-
window.location.href = redirectTo;
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children });
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Guard simples que só renderiza children se estiver autenticado
|
|
58
|
-
*/
|
|
59
|
-
function AuthGuard({ children, fallback, redirectTo }) {
|
|
60
|
-
const { isAuthenticated, isLoading } = (0, react_2.useAuth)();
|
|
61
|
-
if (redirectTo && !isLoading && !isAuthenticated) {
|
|
62
|
-
clientRouter_1.router.push(redirectTo);
|
|
63
|
-
}
|
|
64
|
-
if (isLoading) {
|
|
65
|
-
return fallback || (0, jsx_runtime_1.jsx)("div", {});
|
|
66
|
-
}
|
|
67
|
-
if (!isAuthenticated) {
|
|
68
|
-
return fallback || null;
|
|
69
|
-
}
|
|
70
|
-
return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children });
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Componente para mostrar conteúdo apenas para usuários não autenticados
|
|
74
|
-
*/
|
|
75
|
-
function GuestOnly({ children, fallback, redirectTo }) {
|
|
76
|
-
const { isAuthenticated, isLoading } = (0, react_2.useAuth)();
|
|
77
|
-
if (redirectTo && !isLoading && isAuthenticated) {
|
|
78
|
-
clientRouter_1.router.push(redirectTo);
|
|
79
|
-
}
|
|
80
|
-
if (isLoading || isAuthenticated) {
|
|
81
|
-
return fallback || (0, jsx_runtime_1.jsx)("div", {});
|
|
82
|
-
}
|
|
83
|
-
return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children });
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Hook para redirecionar baseado no status de autenticação
|
|
87
|
-
*/
|
|
88
|
-
function useAuthRedirect(authenticatedRedirect, unauthenticatedRedirect) {
|
|
89
|
-
const { isAuthenticated, isLoading } = (0, react_2.useAuth)();
|
|
90
|
-
react_1.default.useEffect(() => {
|
|
91
|
-
if (isLoading)
|
|
92
|
-
return;
|
|
93
|
-
if (isAuthenticated && authenticatedRedirect) {
|
|
94
|
-
window.location.href = authenticatedRedirect;
|
|
95
|
-
}
|
|
96
|
-
else if (!isAuthenticated && unauthenticatedRedirect) {
|
|
97
|
-
window.location.href = unauthenticatedRedirect;
|
|
98
|
-
}
|
|
99
|
-
}, [isAuthenticated, isLoading, authenticatedRedirect, unauthenticatedRedirect]);
|
|
100
|
-
}
|
package/dist/auth/core.d.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { HightJSRequest, HightJSResponse } from '../api/http';
|
|
2
|
-
import type { AuthConfig, AuthProviderClass, Session } from './types';
|
|
3
|
-
export declare class HWebAuth {
|
|
4
|
-
private config;
|
|
5
|
-
private sessionManager;
|
|
6
|
-
constructor(config: AuthConfig);
|
|
7
|
-
/**
|
|
8
|
-
* Middleware para adicionar autenticação às rotas
|
|
9
|
-
*/
|
|
10
|
-
private middleware;
|
|
11
|
-
/**
|
|
12
|
-
* Autentica um usuário usando um provider específico
|
|
13
|
-
*/
|
|
14
|
-
signIn(providerId: string, credentials: Record<string, string>): Promise<{
|
|
15
|
-
session: Session;
|
|
16
|
-
token: string;
|
|
17
|
-
} | {
|
|
18
|
-
redirectUrl: string;
|
|
19
|
-
} | null>;
|
|
20
|
-
/**
|
|
21
|
-
* Faz logout do usuário
|
|
22
|
-
*/
|
|
23
|
-
signOut(req: HightJSRequest): Promise<HightJSResponse>;
|
|
24
|
-
/**
|
|
25
|
-
* Obtém a sessão atual
|
|
26
|
-
*/
|
|
27
|
-
getSession(req: HightJSRequest): Promise<Session | null>;
|
|
28
|
-
/**
|
|
29
|
-
* Verifica se o usuário está autenticado
|
|
30
|
-
*/
|
|
31
|
-
isAuthenticated(req: HightJSRequest): Promise<boolean>;
|
|
32
|
-
/**
|
|
33
|
-
* Retorna todos os providers disponíveis (dados públicos)
|
|
34
|
-
*/
|
|
35
|
-
getProviders(): any[];
|
|
36
|
-
/**
|
|
37
|
-
* Busca um provider específico
|
|
38
|
-
*/
|
|
39
|
-
getProvider(id: string): AuthProviderClass | null;
|
|
40
|
-
/**
|
|
41
|
-
* Retorna todas as rotas adicionais dos providers
|
|
42
|
-
*/
|
|
43
|
-
getAllAdditionalRoutes(): Array<{
|
|
44
|
-
provider: string;
|
|
45
|
-
route: any;
|
|
46
|
-
}>;
|
|
47
|
-
/**
|
|
48
|
-
* Cria resposta com cookie de autenticação - Secure implementation
|
|
49
|
-
*/
|
|
50
|
-
createAuthResponse(token: string, data: any): HightJSResponse;
|
|
51
|
-
/**
|
|
52
|
-
* Extrai token da requisição (cookie ou header)
|
|
53
|
-
*/
|
|
54
|
-
private getTokenFromRequest;
|
|
55
|
-
}
|