hightjs 0.2.43 → 0.2.45
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 +22 -562
- package/dist/bin/hightjs.js +393 -0
- package/dist/router.js +0 -1
- package/docs/README.md +59 -0
- package/docs/adapters.md +7 -0
- package/docs/arquivos-especiais.md +10 -0
- package/docs/autenticacao.md +212 -0
- package/docs/checklist.md +9 -0
- package/docs/cli.md +21 -0
- package/docs/estrutura.md +20 -0
- package/docs/faq.md +10 -0
- package/docs/hot-reload.md +5 -0
- package/docs/middlewares.md +73 -0
- package/docs/rotas-backend.md +45 -0
- package/docs/rotas-frontend.md +66 -0
- package/docs/seguranca.md +8 -0
- package/docs/websocket.md +45 -0
- package/package.json +1 -1
- package/src/bin/hightjs.js +475 -0
- package/src/router.ts +0 -1
- package/dist/adapters/starters/express.d.ts +0 -0
- package/dist/adapters/starters/express.js +0 -1
- package/dist/adapters/starters/factory.d.ts +0 -0
- package/dist/adapters/starters/factory.js +0 -1
- package/dist/adapters/starters/fastify.d.ts +0 -0
- package/dist/adapters/starters/fastify.js +0 -1
- package/dist/adapters/starters/index.d.ts +0 -0
- package/dist/adapters/starters/index.js +0 -1
- package/dist/adapters/starters/native.d.ts +0 -0
- package/dist/adapters/starters/native.js +0 -1
- package/dist/auth/example.d.ts +0 -40
- package/dist/auth/example.js +0 -104
- package/dist/client/ErrorBoundary.d.ts +0 -16
- package/dist/client/ErrorBoundary.js +0 -181
- package/dist/client/routerContext.d.ts +0 -26
- package/dist/client/routerContext.js +0 -62
- package/dist/eslint/index.d.ts +0 -32
- package/dist/eslint/index.js +0 -15
- package/dist/eslint/use-client-rule.d.ts +0 -19
- package/dist/eslint/use-client-rule.js +0 -99
- package/dist/eslintSetup.d.ts +0 -0
- package/dist/eslintSetup.js +0 -1
- package/dist/example/src/web/routes/index.d.ts +0 -3
- package/dist/example/src/web/routes/index.js +0 -15
- package/dist/hightweb-global.d.ts +0 -0
- package/dist/hightweb-global.js +0 -1
- package/dist/ssl/selfSigned.d.ts +0 -0
- package/dist/ssl/selfSigned.js +0 -1
- package/dist/types/websocket.d.ts +0 -27
- package/dist/types/websocket.js +0 -2
- package/dist/typescript/use-client-plugin.d.ts +0 -5
- package/dist/typescript/use-client-plugin.js +0 -113
- package/dist/validation.d.ts +0 -0
- package/dist/validation.js +0 -1
- package/src/hightweb-global.ts +0 -1
- package/src/ssl/selfSigned.ts +0 -2
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# 🔐 Autenticação (HightJS/auth)
|
|
2
|
+
|
|
3
|
+
Autenticação JWT embutida, fácil de configurar.
|
|
4
|
+
O jeito recomendado é criar as rotas diretamente no `auth.ts` e importar onde quiser.
|
|
5
|
+
|
|
6
|
+
## Configuração Básica & Rotas
|
|
7
|
+
|
|
8
|
+
`src/auth.ts`:
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { CredentialsProvider, DiscordProvider, createAuthRoutes } from 'hightjs/auth';
|
|
12
|
+
import type { AuthConfig } from 'hightjs/auth';
|
|
13
|
+
|
|
14
|
+
export const authConfig: AuthConfig = {
|
|
15
|
+
providers: [
|
|
16
|
+
new CredentialsProvider({
|
|
17
|
+
id: 'credentials',
|
|
18
|
+
name: 'Credentials',
|
|
19
|
+
credentials: {
|
|
20
|
+
username: { label: 'Username', type: 'text', placeholder: 'Digite seu usuário' },
|
|
21
|
+
password: { label: 'Password', type: 'password', placeholder: 'Digite sua senha' }
|
|
22
|
+
},
|
|
23
|
+
async authorize(credentials) {
|
|
24
|
+
if (credentials.username === 'admin' && credentials.password === 'admin') {
|
|
25
|
+
return {
|
|
26
|
+
id: '1',
|
|
27
|
+
username: 'admin',
|
|
28
|
+
email: 'admin@test.com',
|
|
29
|
+
name: 'Administrador',
|
|
30
|
+
testeeee: 'sdondsfndsfndsfodsfo'
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}),
|
|
36
|
+
new DiscordProvider({
|
|
37
|
+
clientId: "ID",
|
|
38
|
+
clientSecret: "TOKEN",
|
|
39
|
+
callbackUrl: "http://localhost:3000/api/auth/callback/discord",
|
|
40
|
+
scope: ['identify', 'email', 'guilds'],
|
|
41
|
+
successUrl: "http://localhost:3000/"
|
|
42
|
+
})
|
|
43
|
+
],
|
|
44
|
+
session: {
|
|
45
|
+
strategy: 'jwt',
|
|
46
|
+
maxAge: 24 * 60 * 60, // 24 horas
|
|
47
|
+
},
|
|
48
|
+
pages: {
|
|
49
|
+
signIn: '/login',
|
|
50
|
+
signOut: '/'
|
|
51
|
+
},
|
|
52
|
+
secret: 'hweb-test-secret-key-change-in-production'
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Cria as rotas de autenticação automaticamente
|
|
56
|
+
export const authRoutes = createAuthRoutes(authConfig);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Exportando as rotas
|
|
60
|
+
|
|
61
|
+
`src/web/backend/routes/auth.ts`:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { authRoutes } from "../../../auth";
|
|
65
|
+
export default authRoutes;
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Configurando o Frontend
|
|
69
|
+
|
|
70
|
+
Para usar autenticação no frontend, você precisa configurar o `SessionProvider` no layout:
|
|
71
|
+
|
|
72
|
+
`src/web/layout.tsx`:
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { SessionProvider } from 'hightjs/auth/react';
|
|
76
|
+
|
|
77
|
+
export const metadata = { title: 'Meu App', descrição: 'Descrição global' };
|
|
78
|
+
|
|
79
|
+
export default function Layout({ children }: { children: React.ReactNode }) {
|
|
80
|
+
return (
|
|
81
|
+
<SessionProvider>
|
|
82
|
+
{children}
|
|
83
|
+
</SessionProvider>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Fazendo Login no Frontend
|
|
89
|
+
|
|
90
|
+
Exemplo de como implementar login com credenciais e Discord:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
import { useSession } from 'hightjs/auth/react';
|
|
94
|
+
import React, { useState } from 'react';
|
|
95
|
+
|
|
96
|
+
function LoginPage() {
|
|
97
|
+
const { signIn } = useSession();
|
|
98
|
+
const [username, setUsername] = useState('');
|
|
99
|
+
const [password, setPassword] = useState('');
|
|
100
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
101
|
+
const [error, setError] = useState<string | null>(null);
|
|
102
|
+
|
|
103
|
+
const handleDiscordLogin = async () => {
|
|
104
|
+
await signIn('discord', { redirect: true });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const handleLogin = async (e: React.FormEvent) => {
|
|
108
|
+
e.preventDefault();
|
|
109
|
+
setIsLoading(true);
|
|
110
|
+
setError(null);
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const result = await signIn('credentials', {
|
|
114
|
+
username: username,
|
|
115
|
+
password: password,
|
|
116
|
+
callbackUrl: '/'
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
if (!result || result.error) {
|
|
120
|
+
setError('Credenciais inválidas. Verifique seus dados e senha.');
|
|
121
|
+
setIsLoading(false);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
router.push("/")
|
|
125
|
+
} catch (err) {
|
|
126
|
+
setError('Ocorreu um erro inesperado. Tente novamente.');
|
|
127
|
+
setIsLoading(false);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<div>
|
|
133
|
+
<form onSubmit={handleLogin}>
|
|
134
|
+
<input
|
|
135
|
+
type="text"
|
|
136
|
+
value={username}
|
|
137
|
+
onChange={(e) => setUsername(e.target.value)}
|
|
138
|
+
placeholder="Username"
|
|
139
|
+
/>
|
|
140
|
+
<input
|
|
141
|
+
type="password"
|
|
142
|
+
value={password}
|
|
143
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
144
|
+
placeholder="Password"
|
|
145
|
+
/>
|
|
146
|
+
<button type="submit" disabled={isLoading}>Login</button>
|
|
147
|
+
</form>
|
|
148
|
+
|
|
149
|
+
<button onClick={handleDiscordLogin}>Login com Discord</button>
|
|
150
|
+
|
|
151
|
+
{error && <p style={{color: 'red'}}>{error}</p>}
|
|
152
|
+
</div>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Acessando Dados do Usuário
|
|
158
|
+
|
|
159
|
+
Para acessar informações do usuário autenticado:
|
|
160
|
+
|
|
161
|
+
```tsx
|
|
162
|
+
import { useSession } from 'hightjs/auth/react';
|
|
163
|
+
|
|
164
|
+
function UserProfile() {
|
|
165
|
+
const { data: session, status, signOut } = useSession();
|
|
166
|
+
|
|
167
|
+
if (status === 'loading') return <p>Carregando...</p>;
|
|
168
|
+
|
|
169
|
+
if (!session) return <p>Não autenticado</p>;
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<div>
|
|
173
|
+
<h1>Bem-vindo, {session.user?.name}</h1>
|
|
174
|
+
<p>Email: {session.user?.email}</p>
|
|
175
|
+
<button onClick={() => signOut()}>Logout</button>
|
|
176
|
+
</div>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Protegendo rotas backend
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
import { HightJSRequest } from "hightjs";
|
|
185
|
+
import { BackendRouteConfig, HightJSResponse } from "hightjs";
|
|
186
|
+
import { authRoutes } from "../../../../auth";
|
|
187
|
+
|
|
188
|
+
const route: BackendRouteConfig = {
|
|
189
|
+
pattern: "/api/version",
|
|
190
|
+
GET: async (req: HightJSRequest, params: any) => {
|
|
191
|
+
const session = await authRoutes.auth.getSession(req)
|
|
192
|
+
if (!session) {
|
|
193
|
+
return HightJSResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
194
|
+
}
|
|
195
|
+
return HightJSResponse.json({
|
|
196
|
+
version: "1.0.0",
|
|
197
|
+
name: "HightJS",
|
|
198
|
+
description: "Um framework web full-stack moderno para Node.js",
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
export default route;
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Métodos principais
|
|
206
|
+
|
|
207
|
+
- `signIn()` - Fazer login (credenciais ou provider)
|
|
208
|
+
- `signOut()` - Fazer logout
|
|
209
|
+
- `useSession()` - Hook para acessar sessão no frontend
|
|
210
|
+
- `authRoutes.auth.getSession()` - Verificar sessão no backend
|
|
211
|
+
- `authRoutes.auth.isAuthenticated()` - Verificar se está autenticado
|
|
212
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# ✅ Checklist Mental
|
|
2
|
+
|
|
3
|
+
1. Precisa de página? Crie em `src/web/routes/...`
|
|
4
|
+
2. Precisa de endpoint? Crie em `src/web/backend/routes/...`
|
|
5
|
+
3. Precisa proteger? Use autenticação nas rotas
|
|
6
|
+
4. Precisa middleware? `middleware.ts` ou `middleware: []` na rota
|
|
7
|
+
5. Metadata? `generateMetadata` ou `metadata` no layout
|
|
8
|
+
6. Deploy? `npx hight start`
|
|
9
|
+
|
package/docs/cli.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# 🛠️ CLI
|
|
2
|
+
|
|
3
|
+
Comandos principais:
|
|
4
|
+
|
|
5
|
+
| Comando | Descrição |
|
|
6
|
+
|--------------------|-------------------------------------------|
|
|
7
|
+
| `npx hight dev` | Modo desenvolvimento (hot reload) |
|
|
8
|
+
| `npx hight start` | Modo produção (usa build gerado) |
|
|
9
|
+
|
|
10
|
+
## Opções
|
|
11
|
+
|
|
12
|
+
- `--port` Porta (default 3000)
|
|
13
|
+
- `--hostname` Host (default 0.0.0.0)
|
|
14
|
+
- `--framework` `native` | `express` | `fastify` (default: native)
|
|
15
|
+
|
|
16
|
+
## Produção
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx hight start -p 8080
|
|
20
|
+
```
|
|
21
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# 📦 Estrutura Recomendada
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
src/
|
|
5
|
+
web/
|
|
6
|
+
layout.tsx // Layout global (opcional)
|
|
7
|
+
notFound.tsx // Página 404 customizada (opcional)
|
|
8
|
+
routes/
|
|
9
|
+
index.tsx // Página inicial "/"
|
|
10
|
+
about.tsx // Página "/about"
|
|
11
|
+
blog.tsx // Rota dinâmica "/blog/123"
|
|
12
|
+
backend/
|
|
13
|
+
routes/
|
|
14
|
+
middleware.ts // Middlewares globais da pasta
|
|
15
|
+
version.ts // Endpoint "/version"
|
|
16
|
+
users/
|
|
17
|
+
middleware.ts // Middlewares só desse grupo
|
|
18
|
+
list.ts // Endpoint "/users/list"
|
|
19
|
+
```
|
|
20
|
+
|
package/docs/faq.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# ❓ FAQ Rápido
|
|
2
|
+
|
|
3
|
+
| Pergunta | Resposta |
|
|
4
|
+
|--------------------------------|-----------------------------------------------------|
|
|
5
|
+
| Precisa Next/Vite? | Não, bundler interno via esbuild. |
|
|
6
|
+
| Dá para usar React 19? | Sim (peer dependency). |
|
|
7
|
+
| Tem SSR? | Atualmente só client-side hydration. |
|
|
8
|
+
| Posso usar CSS/SCSS? | Import normal nos componentes. |
|
|
9
|
+
| Rota de API conflita com página?| Não, rotas backend podem ser qualquer path. |
|
|
10
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# 🧩 Middlewares
|
|
2
|
+
|
|
3
|
+
Adicione middlewares:
|
|
4
|
+
|
|
5
|
+
- Direto na rota: `middleware: [...]`
|
|
6
|
+
- Arquivo `middleware.ts` na pasta (auto-carregado)
|
|
7
|
+
|
|
8
|
+
## Interface
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
export type HightMiddleware = (
|
|
12
|
+
request: HightJSRequest,
|
|
13
|
+
params: { [key: string]: string },
|
|
14
|
+
next: () => Promise<HightJSResponse>
|
|
15
|
+
) => Promise<HightJSResponse> | HightJSResponse;
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Exemplo por Pasta
|
|
19
|
+
|
|
20
|
+
`src/web/backend/routes/middleware.ts`:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import {HightJSRequest, HightJSResponse} from 'hightjs';
|
|
24
|
+
|
|
25
|
+
export async function log(
|
|
26
|
+
request: HightJSRequest,
|
|
27
|
+
params: { [key: string]: string },
|
|
28
|
+
next: () => Promise<HightJSResponse>
|
|
29
|
+
): Promise<HightJSResponse> {
|
|
30
|
+
|
|
31
|
+
console.log('[API]', request.method, request.url);
|
|
32
|
+
return next();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
export async function blockLegacy(
|
|
37
|
+
request: HightJSRequest,
|
|
38
|
+
params: { [key: string]: string },
|
|
39
|
+
next: () => Promise<HightJSResponse>
|
|
40
|
+
): Promise<HightJSResponse> {
|
|
41
|
+
if (request.header('user-agent')?.includes('IE 8')) {
|
|
42
|
+
return HightJSResponse.json({ error: 'Navegador não suportado' }, {status: 400});
|
|
43
|
+
}
|
|
44
|
+
return next();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default [log, blockLegacy];
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Exemplo por Rota
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import {BackendRouteConfig, HightJSRequest, HightJSResponse} from 'hightjs';
|
|
54
|
+
|
|
55
|
+
async function authCheck(
|
|
56
|
+
request: HightJSRequest,
|
|
57
|
+
params: { [key: string]: string },
|
|
58
|
+
next: () => Promise<HightJSResponse>
|
|
59
|
+
): Promise<HightJSResponse> {
|
|
60
|
+
if(!request.header("authorization")) {
|
|
61
|
+
return HightJSResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
62
|
+
}
|
|
63
|
+
return next();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const route: BackendRouteConfig = {
|
|
67
|
+
pattern: '/secure/data',
|
|
68
|
+
middleware: [authCheck],
|
|
69
|
+
GET: async () => HightJSResponse.json({ secret: true })
|
|
70
|
+
};
|
|
71
|
+
export default route;
|
|
72
|
+
```
|
|
73
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# 🌐 Rotas Backend
|
|
2
|
+
|
|
3
|
+
Qualquer arquivo em `src/web/backend/routes` vira endpoint backend.
|
|
4
|
+
O _pattern_ pode ser qualquer caminho, não só `/api/...`!
|
|
5
|
+
|
|
6
|
+
## Exemplo Simples
|
|
7
|
+
|
|
8
|
+
`src/web/backend/routes/version.ts`:
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { HightJSRequest, HightJSResponse, BackendRouteConfig } from 'hightjs';
|
|
12
|
+
|
|
13
|
+
const route: BackendRouteConfig = {
|
|
14
|
+
pattern: '/version',
|
|
15
|
+
GET: async (_req: HightJSRequest) => {
|
|
16
|
+
return HightJSResponse.json({
|
|
17
|
+
version: '1.0.0',
|
|
18
|
+
name: 'HightJS',
|
|
19
|
+
description: 'Framework web full-stack moderno para Node.js'
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
export default route;
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Suporte a Métodos
|
|
27
|
+
|
|
28
|
+
Defina `GET`, `POST`, `PUT`, `DELETE` (ou só os necessários).
|
|
29
|
+
|
|
30
|
+
## Rotas Dinâmicas Backend
|
|
31
|
+
|
|
32
|
+
`src/web/backend/routes/users/[id].ts` → `/users/123`
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { BackendRouteConfig, HightJSResponse } from "hightjs";
|
|
36
|
+
|
|
37
|
+
const route: BackendRouteConfig = {
|
|
38
|
+
pattern: '/users/[id]',
|
|
39
|
+
GET: async (req, params) => {
|
|
40
|
+
return HightJSResponse.json({ userId: params.id });
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
export default route;
|
|
44
|
+
```
|
|
45
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# 🖥️ Rotas Frontend
|
|
2
|
+
|
|
3
|
+
Cada arquivo em `src/web/routes` é uma página.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { RouteConfig } from 'hightjs/client';
|
|
7
|
+
import React from 'react';
|
|
8
|
+
|
|
9
|
+
function Component() {
|
|
10
|
+
return <h1>HELLO WORLD</h1>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const config: RouteConfig = {
|
|
14
|
+
pattern: '/thanks2',
|
|
15
|
+
component: Component,
|
|
16
|
+
generateMetadata: () => ({ title: 'HightJS | Thanks' })
|
|
17
|
+
};
|
|
18
|
+
export default config;
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Rotas Dinâmicas com Parâmetros
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import {RouteConfig} from "hightjs/client";
|
|
25
|
+
import React from "react";
|
|
26
|
+
|
|
27
|
+
function PostPage({ params }: { params: { id: string } }) {
|
|
28
|
+
const id = params.id
|
|
29
|
+
return (
|
|
30
|
+
<div>
|
|
31
|
+
<h1>Post ID: {id}</h1>
|
|
32
|
+
<p>This is the content of post {id}.</p>
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const config: RouteConfig = {
|
|
38
|
+
pattern: '/post/[id]',
|
|
39
|
+
component: PostPage,
|
|
40
|
+
generateMetadata: async (params) => ({ title: `Post ${params.id}` })
|
|
41
|
+
};
|
|
42
|
+
export default config
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Layout Global
|
|
47
|
+
|
|
48
|
+
`src/web/layout.tsx`:
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
export const metadata = { title: 'Meu App', description: 'Descrição global' };
|
|
52
|
+
export default function Layout({ children }: { children: React.ReactNode }) {
|
|
53
|
+
return <div>{children}</div>;
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Página 404
|
|
58
|
+
|
|
59
|
+
`src/web/notFound.tsx`:
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
export default function NotFound() {
|
|
63
|
+
return <h1>Página não encontrada</h1>;
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# 🛜 WebSocket
|
|
2
|
+
|
|
3
|
+
O HightJS possui suporte nativo a WebSockets nas rotas do backend.
|
|
4
|
+
|
|
5
|
+
## Exemplo Prático
|
|
6
|
+
|
|
7
|
+
`src/web/backend/routes/chat.ts`:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import {BackendRouteConfig, HightJSResponse} from 'hightjs';
|
|
11
|
+
|
|
12
|
+
const route: BackendRouteConfig = {
|
|
13
|
+
pattern: '/api/chat',
|
|
14
|
+
GET: async () => {
|
|
15
|
+
return HightJSResponse.json({ message: 'Chat HTTP endpoint' });
|
|
16
|
+
},
|
|
17
|
+
WS: (ctx) => {
|
|
18
|
+
console.log('Nova conexão WebSocket no chat');
|
|
19
|
+
|
|
20
|
+
ctx.send({
|
|
21
|
+
type: 'welcome',
|
|
22
|
+
message: 'Bem-vindo ao chat!'
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
ctx.ws.on('message', (data) => {
|
|
26
|
+
const message = JSON.parse(data.toString());
|
|
27
|
+
console.log(message)
|
|
28
|
+
// Broadcast para todos exceto o remetente
|
|
29
|
+
ctx.broadcast({
|
|
30
|
+
type: 'message',
|
|
31
|
+
user: message.user,
|
|
32
|
+
text: message.text,
|
|
33
|
+
timestamp: new Date().toISOString()
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
ctx.ws.on('close', () => {
|
|
38
|
+
console.log('Cliente desconectado');
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default route;
|
|
44
|
+
```
|
|
45
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hightjs",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.45",
|
|
4
4
|
"description": "HightJS is a high-level framework for building web applications with ease and speed. It provides a robust set of tools and features to streamline development and enhance productivity.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|