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.
Files changed (123) hide show
  1. package/README.md +48 -116
  2. package/dist/bin/hightjs.js +51 -23
  3. package/dist/builder.js +198 -8
  4. package/dist/client/DefaultNotFound.d.ts +1 -1
  5. package/dist/client/DefaultNotFound.js +72 -46
  6. package/dist/client/client.d.ts +3 -0
  7. package/dist/{client.js → client/client.js} +4 -4
  8. package/dist/client/entry.client.js +77 -9
  9. package/dist/global/global.d.ts +117 -0
  10. package/dist/{auth/types.js → global/global.js} +0 -1
  11. package/dist/helpers.js +80 -2
  12. package/dist/hotReload.js +84 -4
  13. package/dist/index.js +72 -61
  14. package/dist/loaders.d.ts +1 -0
  15. package/dist/loaders.js +46 -0
  16. package/dist/renderer.js +158 -4
  17. package/dist/types.d.ts +44 -0
  18. package/package.json +37 -30
  19. package/.idea/HightJS.iml +0 -9
  20. package/.idea/copilot.data.migration.agent.xml +0 -6
  21. package/.idea/copilot.data.migration.ask.xml +0 -6
  22. package/.idea/copilot.data.migration.ask2agent.xml +0 -6
  23. package/.idea/copilot.data.migration.edit.xml +0 -6
  24. package/.idea/copilotDiffState.xml +0 -67
  25. package/.idea/inspectionProfiles/Project_Default.xml +0 -13
  26. package/.idea/libraries/test_package.xml +0 -9
  27. package/.idea/libraries/ts_commonjs_default_export.xml +0 -9
  28. package/.idea/misc.xml +0 -7
  29. package/.idea/modules.xml +0 -8
  30. package/.idea/vcs.xml +0 -6
  31. package/dist/auth/client.d.ts +0 -24
  32. package/dist/auth/client.js +0 -146
  33. package/dist/auth/components.d.ts +0 -29
  34. package/dist/auth/components.js +0 -100
  35. package/dist/auth/core.d.ts +0 -55
  36. package/dist/auth/core.js +0 -189
  37. package/dist/auth/index.d.ts +0 -7
  38. package/dist/auth/index.js +0 -45
  39. package/dist/auth/jwt.d.ts +0 -41
  40. package/dist/auth/jwt.js +0 -185
  41. package/dist/auth/providers/credentials.d.ts +0 -60
  42. package/dist/auth/providers/credentials.js +0 -97
  43. package/dist/auth/providers/discord.d.ts +0 -63
  44. package/dist/auth/providers/discord.js +0 -190
  45. package/dist/auth/providers/google.d.ts +0 -63
  46. package/dist/auth/providers/google.js +0 -186
  47. package/dist/auth/providers/index.d.ts +0 -2
  48. package/dist/auth/providers/index.js +0 -35
  49. package/dist/auth/providers.d.ts +0 -3
  50. package/dist/auth/providers.js +0 -26
  51. package/dist/auth/react/index.d.ts +0 -6
  52. package/dist/auth/react/index.js +0 -48
  53. package/dist/auth/react.d.ts +0 -22
  54. package/dist/auth/react.js +0 -199
  55. package/dist/auth/routes.d.ts +0 -16
  56. package/dist/auth/routes.js +0 -152
  57. package/dist/auth/types.d.ts +0 -76
  58. package/dist/client.d.ts +0 -3
  59. package/docs/README.md +0 -58
  60. package/docs/arquivos-especiais.md +0 -10
  61. package/docs/autenticacao.md +0 -212
  62. package/docs/checklist.md +0 -9
  63. package/docs/cli.md +0 -72
  64. package/docs/config.md +0 -216
  65. package/docs/estrutura.md +0 -20
  66. package/docs/faq.md +0 -10
  67. package/docs/hot-reload.md +0 -5
  68. package/docs/integracoes.md +0 -240
  69. package/docs/middlewares.md +0 -73
  70. package/docs/rotas-backend.md +0 -45
  71. package/docs/rotas-frontend.md +0 -66
  72. package/docs/seguranca.md +0 -8
  73. package/docs/websocket.md +0 -45
  74. package/example/certs/cert.pem +0 -20
  75. package/example/certs/key.pem +0 -27
  76. package/example/hightjs.config.ts +0 -87
  77. package/example/package-lock.json +0 -1174
  78. package/example/package.json +0 -26
  79. package/example/postcss.config.js +0 -8
  80. package/example/src/auth.ts +0 -42
  81. package/example/src/web/backend/routes/auth.ts +0 -3
  82. package/example/src/web/backend/routes/version.ts +0 -13
  83. package/example/src/web/globals.css +0 -5
  84. package/example/src/web/layout.tsx +0 -100
  85. package/example/src/web/routes/index.tsx +0 -153
  86. package/example/src/web/routes/login.tsx +0 -175
  87. package/example/tailwind.config.js +0 -12
  88. package/example/tsconfig.json +0 -15
  89. package/src/adapters/express.ts +0 -87
  90. package/src/adapters/factory.ts +0 -112
  91. package/src/adapters/fastify.ts +0 -104
  92. package/src/adapters/native.ts +0 -234
  93. package/src/api/console.ts +0 -305
  94. package/src/api/http.ts +0 -535
  95. package/src/auth/client.ts +0 -171
  96. package/src/auth/components.tsx +0 -125
  97. package/src/auth/core.ts +0 -215
  98. package/src/auth/index.ts +0 -25
  99. package/src/auth/jwt.ts +0 -210
  100. package/src/auth/providers/credentials.ts +0 -139
  101. package/src/auth/providers/discord.ts +0 -239
  102. package/src/auth/providers/google.ts +0 -234
  103. package/src/auth/providers/index.ts +0 -20
  104. package/src/auth/providers.ts +0 -20
  105. package/src/auth/react/index.ts +0 -25
  106. package/src/auth/react.tsx +0 -234
  107. package/src/auth/routes.ts +0 -183
  108. package/src/auth/types.ts +0 -108
  109. package/src/bin/hightjs.js +0 -222
  110. package/src/builder.js +0 -411
  111. package/src/client/DefaultNotFound.tsx +0 -84
  112. package/src/client/clientRouter.ts +0 -153
  113. package/src/client/entry.client.tsx +0 -444
  114. package/src/client.ts +0 -24
  115. package/src/components/Link.tsx +0 -38
  116. package/src/helpers.ts +0 -542
  117. package/src/hotReload.ts +0 -489
  118. package/src/index.ts +0 -546
  119. package/src/renderer.tsx +0 -263
  120. package/src/router.ts +0 -730
  121. package/src/types/framework.ts +0 -58
  122. package/src/types.ts +0 -207
  123. 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';&#10;import { WebSocket } from 'ws';&#10;&#10;export interface WebSocketContext {&#10; ws: WebSocket;&#10; req: IncomingMessage;&#10; url: URL;&#10; params: Record&lt;string, string&gt;;&#10; query: Record&lt;string, string&gt;;&#10; send: (data: any) =&gt; void;&#10; close: (code?: number, reason?: string) =&gt; void;&#10; broadcast: (data: any, exclude?: WebSocket[]) =&gt; void;&#10;}&#10;&#10;export interface WebSocketHandler {&#10; (ctx: WebSocketContext): void | Promise&lt;void&gt;;&#10;}&#10;&#10;export interface WebSocketRoute {&#10; path: string;&#10; handler: WebSocketHandler;&#10; pathPattern?: RegExp;&#10; paramNames?: string[];&#10;}&#10;&#10;export interface WebSocketServer {&#10; route: (path: string, handler: WebSocketHandler) =&gt; void;&#10; start: (port?: number) =&gt; void;&#10; broadcast: (data: any) =&gt; void;&#10; getConnections: () =&gt; WebSocket[];&#10;}" />
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';&#10;import { WebSocketServer as WSServer } from 'ws';&#10;import { HightWSServer } from './server';&#10;import { WebSocketServer, WebSocketHandler } from '../types/websocket';&#10;import Console, { Colors } from '../api/console';&#10;&#10;export class WebSocketAdapter {&#10; private wsServer: HightWSServer;&#10; private httpServer: Server | null = null;&#10; private wss: WSServer | null = null;&#10;&#10; constructor() {&#10; this.wsServer = new HightWSServer();&#10; }&#10;&#10; /**&#10; * Integra WebSocket com um servidor HTTP existente&#10; */&#10; attachToHttpServer(httpServer: Server): void {&#10; this.httpServer = httpServer;&#10; this.wss = new WSServer({ &#10; server: httpServer,&#10; perMessageDeflate: false &#10; });&#10;&#10; console.log(`${Colors.FgGreen}✓${Colors.Reset} WebSocket attached to HTTP server`);&#10;&#10; this.wss.on('connection', (ws, req) =&gt; {&#10; this.wsServer['handleConnection'](ws, req);&#10; });&#10;&#10; this.wss.on('error', (error) =&gt; {&#10; console.error(`${Colors.FgRed}[WebSocket Server Error]${Colors.Reset}`, error);&#10; });&#10; }&#10;&#10; /**&#10; * Adiciona uma rota WebSocket&#10; */&#10; route(path: string, handler: WebSocketHandler): void {&#10; this.wsServer.route(path, handler);&#10; }&#10;&#10; /**&#10; * Faz broadcast para todas as conexões&#10; */&#10; broadcast(data: any): void {&#10; this.wsServer.broadcast(data);&#10; }&#10;&#10; /**&#10; * Retorna todas as conexões ativas&#10; */&#10; getConnections() {&#10; return this.wsServer.getConnections();&#10; }&#10;&#10; /**&#10; * Inicia servidor WebSocket standalone&#10; */&#10; startStandalone(port: number = 8080): void {&#10; this.wsServer.start(port);&#10; }&#10;}" />
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="&#10;" />
27
- <option name="updatedContent" value="import React from 'react';&#10;&#10;export class HightWSClient {&#10; private ws: WebSocket | null = null;&#10; private url: string;&#10; private reconnectAttempts: number = 0;&#10; private maxReconnectAttempts: number = 5;&#10; private reconnectDelay: number = 1000;&#10; private listeners: Map&lt;string, Function[]&gt; = new Map();&#10;&#10; constructor(url: string) {&#10; this.url = url;&#10; this.connect();&#10; }&#10;&#10; private connect(): void {&#10; try {&#10; this.ws = new WebSocket(this.url);&#10; &#10; this.ws.onopen = (event) =&gt; {&#10; console.log('[HightWS] Connected to WebSocket server');&#10; this.reconnectAttempts = 0;&#10; this.emit('open', event);&#10; };&#10;&#10; this.ws.onmessage = (event) =&gt; {&#10; try {&#10; const data = JSON.parse(event.data);&#10; this.emit('message', data);&#10; } catch (error) {&#10; // Se não for JSON, envia como string&#10; this.emit('message', event.data);&#10; }&#10; };&#10;&#10; this.ws.onclose = (event) =&gt; {&#10; console.log('[HightWS] Connection closed');&#10; this.emit('close', event);&#10; this.attemptReconnect();&#10; };&#10;&#10; this.ws.onerror = (event) =&gt; {&#10; console.error('[HightWS] WebSocket error:', event);&#10; this.emit('error', event);&#10; };&#10;&#10; } catch (error) {&#10; console.error('[HightWS] Failed to connect:', error);&#10; this.attemptReconnect();&#10; }&#10; }&#10;&#10; private attemptReconnect(): void {&#10; if (this.reconnectAttempts &lt; this.maxReconnectAttempts) {&#10; this.reconnectAttempts++;&#10; console.log(`[HightWS] Attempting to reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`);&#10; &#10; setTimeout(() =&gt; {&#10; this.connect();&#10; }, this.reconnectDelay * this.reconnectAttempts);&#10; } else {&#10; console.error('[HightWS] Max reconnection attempts reached');&#10; this.emit('maxReconnectAttemptsReached');&#10; }&#10; }&#10;&#10; public send(data: any): void {&#10; if (this.ws &amp;&amp; this.ws.readyState === WebSocket.OPEN) {&#10; const message = typeof data === 'string' ? data : JSON.stringify(data);&#10; this.ws.send(message);&#10; } else {&#10; console.warn('[HightWS] WebSocket is not connected');&#10; }&#10; }&#10;&#10; public on(event: string, callback: Function): void {&#10; if (!this.listeners.has(event)) {&#10; this.listeners.set(event, []);&#10; }&#10; this.listeners.get(event)!.push(callback);&#10; }&#10;&#10; public off(event: string, callback?: Function): void {&#10; if (!this.listeners.has(event)) return;&#10;&#10; if (callback) {&#10; const callbacks = this.listeners.get(event)!;&#10; const index = callbacks.indexOf(callback);&#10; if (index &gt; -1) {&#10; callbacks.splice(index, 1);&#10; }&#10; } else {&#10; this.listeners.delete(event);&#10; }&#10; }&#10;&#10; private emit(event: string, data?: any): void {&#10; if (this.listeners.has(event)) {&#10; this.listeners.get(event)!.forEach(callback =&gt; {&#10; try {&#10; callback(data);&#10; } catch (error) {&#10; console.error(`[HightWS] Error in event listener for ${event}:`, error);&#10; }&#10; });&#10; }&#10; }&#10;&#10; public close(): void {&#10; if (this.ws) {&#10; this.ws.close();&#10; this.ws = null;&#10; }&#10; }&#10;&#10; public get readyState(): number {&#10; return this.ws ? this.ws.readyState : WebSocket.CLOSED;&#10; }&#10;&#10; public get isConnected(): boolean {&#10; return this.ws !== null &amp;&amp; this.ws.readyState === WebSocket.OPEN;&#10; }&#10;}&#10;&#10;// Hook React para usar WebSocket&#10;export function useWebSocket(url: string) {&#10; const [client, setClient] = React.useState&lt;HightWSClient | null&gt;(null);&#10; const [isConnected, setIsConnected] = React.useState(false);&#10; const [lastMessage, setLastMessage] = React.useState&lt;any&gt;(null);&#10;&#10; React.useEffect(() =&gt; {&#10; const wsClient = new HightWSClient(url);&#10;&#10; wsClient.on('open', () =&gt; {&#10; setIsConnected(true);&#10; });&#10;&#10; wsClient.on('close', () =&gt; {&#10; setIsConnected(false);&#10; });&#10;&#10; wsClient.on('message', (data) =&gt; {&#10; setLastMessage(data);&#10; });&#10;&#10; setClient(wsClient);&#10;&#10; return () =&gt; {&#10; wsClient.close();&#10; };&#10; }, [url]);&#10;&#10; const sendMessage = React.useCallback((data: any) =&gt; {&#10; if (client) {&#10; client.send(data);&#10; }&#10; }, [client]);&#10;&#10; return {&#10; client,&#10; isConnected,&#10; lastMessage,&#10; sendMessage&#10; };&#10;}" />
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&#10;&#10;// ============================================&#10;// BACKEND - Como criar rotas WebSocket&#10;// ============================================&#10;&#10;// Em src/web/backend/websocket.ts (ou qualquer arquivo backend)&#10;import { ws } from 'hightjs/ws';&#10;&#10;// Rota simples de chat&#10;ws('/chat', (ctx) =&gt; {&#10; console.log('Nova conexão no chat:', ctx.req.socket.remoteAddress);&#10; &#10; // Envia mensagem de boas-vindas&#10; ctx.send({&#10; type: 'welcome',&#10; message: 'Bem-vindo ao chat!'&#10; });&#10;&#10; // Escuta mensagens do cliente&#10; ctx.ws.on('message', (data) =&gt; {&#10; try {&#10; const message = JSON.parse(data.toString());&#10; &#10; // Faz broadcast da mensagem para todos os outros clientes&#10; ctx.broadcast({&#10; type: 'message',&#10; user: message.user || 'Anônimo',&#10; text: message.text,&#10; timestamp: new Date().toISOString()&#10; }, [ctx.ws]); // Exclui o remetente&#10; &#10; } catch (error) {&#10; console.error('Erro ao processar mensagem:', error);&#10; }&#10; });&#10;&#10; // Quando a conexão fechar&#10; ctx.ws.on('close', () =&gt; {&#10; console.log('Cliente desconectado do chat');&#10; });&#10;});&#10;&#10;// Rota com parâmetros&#10;ws('/room/:roomId', (ctx) =&gt; {&#10; const { roomId } = ctx.params;&#10; console.log(`Nova conexão na sala: ${roomId}`);&#10; &#10; ctx.send({&#10; type: 'joined',&#10; room: roomId,&#10; message: `Você entrou na sala ${roomId}`&#10; });&#10;});&#10;&#10;// Rota para notificações em tempo real&#10;ws('/notifications/:userId', (ctx) =&gt; {&#10; const { userId } = ctx.params;&#10; &#10; // Pode usar query params também&#10; const token = ctx.query.token;&#10; &#10; if (!token) {&#10; ctx.close(1008, 'Token obrigatório');&#10; return;&#10; }&#10; &#10; console.log(`Usuário ${userId} conectado para notificações`);&#10; &#10; // Simula envio de notificação a cada 30 segundos&#10; const interval = setInterval(() =&gt; {&#10; ctx.send({&#10; type: 'notification',&#10; title: 'Nova notificação',&#10; body: 'Você tem uma nova mensagem',&#10; timestamp: new Date().toISOString()&#10; });&#10; }, 30000);&#10; &#10; ctx.ws.on('close', () =&gt; {&#10; clearInterval(interval);&#10; console.log(`Usuário ${userId} desconectado das notificações`);&#10; });&#10;});&#10;&#10;// ============================================&#10;// FRONTEND - Como usar WebSocket no React&#10;// ============================================&#10;&#10;// Em qualquer componente React&#10;import React from 'react';&#10;import { HightWSClient, useWebSocket } from 'hightjs/ws';&#10;&#10;// Método 1: Usando o hook useWebSocket (mais fácil)&#10;function ChatComponent() {&#10; const { client, isConnected, lastMessage, sendMessage } = useWebSocket('ws://localhost:8080/chat');&#10; const [messages, setMessages] = React.useState([]);&#10; const [newMessage, setNewMessage] = React.useState('');&#10;&#10; // Atualiza mensagens quando recebe uma nova&#10; React.useEffect(() =&gt; {&#10; if (lastMessage &amp;&amp; lastMessage.type === 'message') {&#10; setMessages(prev =&gt; [...prev, lastMessage]);&#10; }&#10; }, [lastMessage]);&#10;&#10; const handleSendMessage = () =&gt; {&#10; if (newMessage.trim() &amp;&amp; isConnected) {&#10; sendMessage({&#10; user: 'Seu Nome',&#10; text: newMessage&#10; });&#10; setNewMessage('');&#10; }&#10; };&#10;&#10; return (&#10; &lt;div&gt;&#10; &lt;div&gt;Status: {isConnected ? 'Conectado' : 'Desconectado'}&lt;/div&gt;&#10; &#10; &lt;div style={{ height: '300px', overflow: 'auto', border: '1px solid #ccc' }}&gt;&#10; {messages.map((msg, index) =&gt; (&#10; &lt;div key={index}&gt;&#10; &lt;strong&gt;{msg.user}:&lt;/strong&gt; {msg.text}&#10; &lt;small&gt; ({new Date(msg.timestamp).toLocaleTimeString()})&lt;/small&gt;&#10; &lt;/div&gt;&#10; ))}&#10; &lt;/div&gt;&#10; &#10; &lt;div&gt;&#10; &lt;input&#10; value={newMessage}&#10; onChange={(e) =&gt; setNewMessage(e.target.value)}&#10; onKeyPress={(e) =&gt; e.key === 'Enter' &amp;&amp; handleSendMessage()}&#10; placeholder=&quot;Digite sua mensagem...&quot;&#10; /&gt;&#10; &lt;button onClick={handleSendMessage} disabled={!isConnected}&gt;&#10; Enviar&#10; &lt;/button&gt;&#10; &lt;/div&gt;&#10; &lt;/div&gt;&#10; );&#10;}&#10;&#10;// Método 2: Usando a classe HightWSClient diretamente (mais controle)&#10;function NotificationsComponent() {&#10; const [client, setClient] = React.useState(null);&#10; const [notifications, setNotifications] = React.useState([]);&#10; const userId = '123'; // ID do usuário atual&#10;&#10; React.useEffect(() =&gt; {&#10; const wsClient = new HightWSClient(`ws://localhost:8080/notifications/${userId}?token=abc123`);&#10; &#10; wsClient.on('open', () =&gt; {&#10; console.log('Conectado às notificações');&#10; });&#10;&#10; wsClient.on('message', (data) =&gt; {&#10; if (data.type === 'notification') {&#10; setNotifications(prev =&gt; [data, ...prev.slice(0, 9)]); // Mantém só as 10 últimas&#10; &#10; // Pode mostrar notificação do browser também&#10; if (Notification.permission === 'granted') {&#10; new Notification(data.title, { body: data.body });&#10; }&#10; }&#10; });&#10;&#10; wsClient.on('close', () =&gt; {&#10; console.log('Desconectado das notificações');&#10; });&#10;&#10; setClient(wsClient);&#10;&#10; return () =&gt; {&#10; wsClient.close();&#10; };&#10; }, [userId]);&#10;&#10; return (&#10; &lt;div&gt;&#10; &lt;h3&gt;Notificações em tempo real&lt;/h3&gt;&#10; {notifications.map((notif, index) =&gt; (&#10; &lt;div key={index} style={{ padding: '10px', border: '1px solid #ddd', margin: '5px 0' }}&gt;&#10; &lt;strong&gt;{notif.title}&lt;/strong&gt;&#10; &lt;p&gt;{notif.body}&lt;/p&gt;&#10; &lt;small&gt;{new Date(notif.timestamp).toLocaleString()}&lt;/small&gt;&#10; &lt;/div&gt;&#10; ))}&#10; &lt;/div&gt;&#10; );&#10;}&#10;&#10;// ============================================&#10;// INICIANDO O SERVIDOR WEBSOCKET&#10;// ============================================&#10;&#10;// No seu arquivo principal de servidor (onde você inicia o HightJS)&#10;import { createWebSocketServer } from 'hightjs/ws';&#10;&#10;// Método 1: Servidor WebSocket independente&#10;const wsServer = createWebSocketServer();&#10;wsServer.start(8080); // Inicia na porta 8080&#10;&#10;// Método 2: Integrar com servidor HTTP existente (Express/Fastify)&#10;// Isso ainda precisa ser implementado nos adapters, mas a estrutura está pronta&#10;&#10;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';&#10;import { WebSocketServer } from '../types/websocket';&#10;&#10;/**&#10; * Cria uma nova instância do servidor WebSocket HightJS&#10; * @returns Uma nova instância do servidor WebSocket&#10; */&#10;export function createWebSocketServer(): WebSocketServer {&#10; return new HightWSServer();&#10;}&#10;&#10;/**&#10; * Instância global do servidor WebSocket (singleton)&#10; */&#10;let globalWSServer: WebSocketServer | null = null;&#10;&#10;/**&#10; * Retorna a instância global do servidor WebSocket ou cria uma nova&#10; * @returns A instância global do servidor WebSocket&#10; */&#10;export function getGlobalWebSocketServer(): WebSocketServer {&#10; if (!globalWSServer) {&#10; globalWSServer = new HightWSServer();&#10; }&#10; return globalWSServer;&#10;}&#10;&#10;/**&#10; * Helper para criar rotas WebSocket rapidamente&#10; * @param path Caminho da rota&#10; * @param handler Função handler da rota&#10; */&#10;export function ws(path: string, handler: (ctx: any) =&gt; void | Promise&lt;void&gt;) {&#10; const server = getGlobalWebSocketServer();&#10; server.route(path, handler);&#10; return server;&#10;}" />
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="&#10;&#10;" />
52
- <option name="updatedContent" value="export { HightWSServer } from './server';&#10;export { WebSocketContext, WebSocketHandler, WebSocketRoute, WebSocketServer } from '../types/websocket';&#10;export { createWebSocketServer } from './factory';&#10;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';&#10;import { IncomingMessage } from 'http';&#10;import { URL } from 'url';&#10;import { WebSocketContext, WebSocketHandler, WebSocketRoute, WebSocketServer } from '../types/websocket';&#10;import Console, { Colors } from '../api/console';&#10;&#10;export class HightWSServer implements WebSocketServer {&#10; private wss: WSServer | null = null;&#10; private routes: WebSocketRoute[] = [];&#10; private connections: Set&lt;WebSocket&gt; = new Set();&#10;&#10; constructor() {&#10; this.setupRoutePatterns();&#10; }&#10;&#10; route(path: string, handler: WebSocketHandler): void {&#10; const route: WebSocketRoute = {&#10; path,&#10; handler,&#10; ...this.createPathPattern(path)&#10; };&#10; this.routes.push(route);&#10; console.log(`${Colors.FgBlue}[WebSocket]${Colors.Reset} Route registered: ${Colors.FgYellow}${path}${Colors.Reset}`);&#10; }&#10;&#10; start(port: number = 8080): void {&#10; this.wss = new WSServer({ &#10; port,&#10; perMessageDeflate: false &#10; });&#10;&#10; console.log(`${Colors.FgGreen}✓${Colors.Reset} WebSocket server listening on port ${Colors.FgYellow}${port}${Colors.Reset}`);&#10;&#10; this.wss.on('connection', (ws: WebSocket, req: IncomingMessage) =&gt; {&#10; this.connections.add(ws);&#10; console.log(`${Colors.FgBlue}[WebSocket]${Colors.Reset} New connection from ${req.socket.remoteAddress}`);&#10;&#10; ws.on('close', () =&gt; {&#10; this.connections.delete(ws);&#10; console.log(`${Colors.FgBlue}[WebSocket]${Colors.Reset} Connection closed`);&#10; });&#10;&#10; ws.on('error', (error) =&gt; {&#10; console.error(`${Colors.FgRed}[WebSocket Error]${Colors.Reset}`, error);&#10; this.connections.delete(ws);&#10; });&#10;&#10; this.handleConnection(ws, req);&#10; });&#10;&#10; this.wss.on('error', (error) =&gt; {&#10; console.error(`${Colors.FgRed}[WebSocket Server Error]${Colors.Reset}`, error);&#10; });&#10; }&#10;&#10; broadcast(data: any): void {&#10; const message = typeof data === 'string' ? data : JSON.stringify(data);&#10; this.connections.forEach(ws =&gt; {&#10; if (ws.readyState === WebSocket.OPEN) {&#10; ws.send(message);&#10; }&#10; });&#10; }&#10;&#10; getConnections(): WebSocket[] {&#10; return Array.from(this.connections);&#10; }&#10;&#10; private handleConnection(ws: WebSocket, req: IncomingMessage): void {&#10; if (!req.url) return;&#10;&#10; const url = new URL(req.url, `http://${req.headers.host}`);&#10; const pathname = url.pathname;&#10;&#10; // Encontra a rota correspondente&#10; const matchedRoute = this.findMatchingRoute(pathname);&#10; if (!matchedRoute) {&#10; console.log(`${Colors.FgYellow}[WebSocket]${Colors.Reset} No route found for ${pathname}`);&#10; ws.close(1000, 'No route found');&#10; return;&#10; }&#10;&#10; // Extrai parâmetros da URL&#10; const params = this.extractParams(pathname, matchedRoute);&#10; const query = Object.fromEntries(url.searchParams.entries());&#10;&#10; // Cria o contexto&#10; const context: WebSocketContext = {&#10; ws,&#10; req,&#10; url,&#10; params,&#10; query,&#10; send: (data: any) =&gt; {&#10; if (ws.readyState === WebSocket.OPEN) {&#10; const message = typeof data === 'string' ? data : JSON.stringify(data);&#10; ws.send(message);&#10; }&#10; },&#10; close: (code?: number, reason?: string) =&gt; {&#10; ws.close(code || 1000, reason);&#10; },&#10; broadcast: (data: any, exclude?: WebSocket[]) =&gt; {&#10; const message = typeof data === 'string' ? data : JSON.stringify(data);&#10; const excludeSet = new Set(exclude || []);&#10; this.connections.forEach(connection =&gt; {&#10; if (connection.readyState === WebSocket.OPEN &amp;&amp; !excludeSet.has(connection)) {&#10; connection.send(message);&#10; }&#10; });&#10; }&#10; };&#10;&#10; try {&#10; matchedRoute.handler(context);&#10; } catch (error) {&#10; console.error(`${Colors.FgRed}[WebSocket Handler Error]${Colors.Reset}`, error);&#10; ws.close(1011, 'Internal server error');&#10; }&#10; }&#10;&#10; private createPathPattern(path: string): { pathPattern: RegExp; paramNames: string[] } {&#10; const paramNames: string[] = [];&#10; const pattern = path&#10; .replace(/\//g, '\\/')&#10; .replace(/:([^\/]+)/g, (_, paramName) =&gt; {&#10; paramNames.push(paramName);&#10; return '([^/]+)';&#10; })&#10; .replace(/\*/g, '.*');&#10;&#10; return {&#10; pathPattern: new RegExp(`^${pattern}$`),&#10; paramNames&#10; };&#10; }&#10;&#10; private findMatchingRoute(pathname: string): WebSocketRoute | null {&#10; return this.routes.find(route =&gt; {&#10; if (route.pathPattern) {&#10; return route.pathPattern.test(pathname);&#10; }&#10; return route.path === pathname;&#10; }) || null;&#10; }&#10;&#10; private extractParams(pathname: string, route: WebSocketRoute): Record&lt;string, string&gt; {&#10; const params: Record&lt;string, string&gt; = {};&#10; &#10; if (route.pathPattern &amp;&amp; route.paramNames) {&#10; const match = pathname.match(route.pathPattern);&#10; if (match) {&#10; route.paramNames.forEach((paramName, index) =&gt; {&#10; params[paramName] = match[index + 1];&#10; });&#10; }&#10; }&#10;&#10; return params;&#10; }&#10;&#10; private setupRoutePatterns(): void {&#10; // Reprocessa todos os patterns das rotas existentes&#10; this.routes.forEach(route =&gt; {&#10; const { pathPattern, paramNames } = this.createPathPattern(route.path);&#10; route.pathPattern = pathPattern;&#10; route.paramNames = paramNames;&#10; });&#10; }&#10;}" />
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>
@@ -1,9 +0,0 @@
1
- <component name="libraryTable">
2
- <library name="test-package">
3
- <CLASSES>
4
- <root url="jar://$PROJECT_DIR$/node_modules/thread-stream/test/dir with spaces/test-package.zip!/" />
5
- </CLASSES>
6
- <JAVADOC />
7
- <SOURCES />
8
- </library>
9
- </component>
@@ -1,9 +0,0 @@
1
- <component name="libraryTable">
2
- <library name="ts-commonjs-default-export">
3
- <CLASSES>
4
- <root url="jar://$PROJECT_DIR$/node_modules/thread-stream/test/ts-commonjs-default-export.zip!/" />
5
- </CLASSES>
6
- <JAVADOC />
7
- <SOURCES />
8
- </library>
9
- </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
@@ -1,8 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="ProjectModuleManager">
4
- <modules>
5
- <module fileurl="file://$PROJECT_DIR$/.idea/HightJS.iml" filepath="$PROJECT_DIR$/.idea/HightJS.iml" />
6
- </modules>
7
- </component>
8
- </project>
package/.idea/vcs.xml DELETED
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="VcsDirectoryMappings">
4
- <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
- </component>
6
- </project>
@@ -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>;
@@ -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 {};
@@ -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
- }
@@ -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
- }