hightjs 0.2.42 → 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/.idea/copilotDiffState.xml +67 -0
- package/README.md +26 -514
- package/dist/auth/core.js +3 -3
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.js +2 -1
- package/dist/auth/providers/google.d.ts +63 -0
- package/dist/auth/providers/google.js +186 -0
- package/dist/auth/providers.d.ts +1 -0
- package/dist/auth/providers.js +3 -1
- package/dist/auth/types.d.ts +6 -7
- package/dist/bin/hightjs.js +393 -0
- package/dist/client/entry.client.js +11 -1
- package/dist/hotReload.d.ts +8 -1
- package/dist/hotReload.js +304 -144
- package/dist/index.d.ts +2 -1
- package/dist/index.js +20 -33
- package/dist/renderer.js +1 -1
- package/dist/router.d.ts +24 -1
- package/dist/router.js +201 -2
- package/dist/types.d.ts +19 -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/auth/core.ts +3 -3
- package/src/auth/index.ts +2 -3
- package/src/auth/providers/google.ts +218 -0
- package/src/auth/providers.ts +1 -1
- package/src/auth/types.ts +3 -8
- package/src/bin/hightjs.js +475 -0
- package/src/client/entry.client.tsx +12 -1
- package/src/hotReload.ts +333 -147
- package/src/index.ts +58 -51
- package/src/renderer.tsx +1 -1
- package/src/router.ts +230 -3
- package/src/types.ts +24 -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/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/auth/example.ts +0 -115
package/README.md
CHANGED
|
@@ -20,24 +20,17 @@ Caso tenha alguma dúvida, entre em contato por uma das redes abaixo:
|
|
|
20
20
|
|
|
21
21
|
- [✨ Principais Recursos](#-principais-recursos)
|
|
22
22
|
- [🚀 Início Rápido](#-início-rápido)
|
|
23
|
-
- [
|
|
24
|
-
- [🖥️ Rotas Frontend (Páginas)](#-rotas-frontend)
|
|
25
|
-
- [🌐 Rotas Backend (API)](#-rotas-backend)
|
|
26
|
-
- [🧩 Middlewares](#-middlewares)
|
|
27
|
-
- [🔐 Autenticação (HightJS/auth)](#-autenticação-hightjsauth)
|
|
28
|
-
- [🛠️ CLI](#-cli)
|
|
29
|
-
- [📂 Arquivos Especiais](#-arquivos-especiais)
|
|
30
|
-
- [🧱 Adapters](#-adapters)
|
|
31
|
-
- [🔐 Segurança Interna](#-segurança-interna)
|
|
32
|
-
- [♻️ Hot Reload](#-hot-reload)
|
|
33
|
-
- [❓ FAQ Rápido](#-faq-rápido)
|
|
34
|
-
- [✅ Checklist Mental](#-checklist-mental)
|
|
23
|
+
- [📚 Documentação](#-documentação)
|
|
35
24
|
- [🪪 Licença](#-licença)
|
|
36
25
|
---
|
|
37
26
|
|
|
38
27
|
## ✨ Principais Recursos
|
|
39
28
|
|
|
40
29
|
- **Roteamento automático** de páginas [`src/web/routes`] e APIs [`src/web/backend/routes`]
|
|
30
|
+
- **React 19** com client-side hydration
|
|
31
|
+
- **TypeScript** first (totalmente tipado)
|
|
32
|
+
- **WebSockets** nativo nas rotas backend
|
|
33
|
+
- **Rotas dinâmicas** com parâmetros (frontend e backend)
|
|
41
34
|
- **Middlewares** por pasta ou rota
|
|
42
35
|
- **Hot Reload** nativo (WebSocket interno) em dev
|
|
43
36
|
- **Layouts globais** e página 404 customizada
|
|
@@ -120,513 +113,30 @@ Acesse: [http://localhost:3000](http://localhost:3000)
|
|
|
120
113
|
|
|
121
114
|
---
|
|
122
115
|
|
|
123
|
-
##
|
|
116
|
+
## 📚 Documentação
|
|
124
117
|
|
|
125
|
-
|
|
126
|
-
src/
|
|
127
|
-
web/
|
|
128
|
-
layout.tsx // Layout global (opcional)
|
|
129
|
-
notFound.tsx // Página 404 customizada (opcional)
|
|
130
|
-
routes/
|
|
131
|
-
index.tsx // Página inicial "/"
|
|
132
|
-
about.tsx // Página "/about"
|
|
133
|
-
blog.tsx // Rota dinâmica "/blog/123"
|
|
134
|
-
backend/
|
|
135
|
-
routes/
|
|
136
|
-
middleware.ts // Middlewares globais da pasta
|
|
137
|
-
version.ts // Endpoint "/version"
|
|
138
|
-
users/
|
|
139
|
-
middleware.ts // Middlewares só desse grupo
|
|
140
|
-
list.ts // Endpoint "/users/list"
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
## 🖥️ Rotas Frontend
|
|
146
|
-
|
|
147
|
-
Cada arquivo em `src/web/routes` é uma página.
|
|
148
|
-
|
|
149
|
-
```tsx
|
|
150
|
-
import { RouteConfig } from 'hightjs/client';
|
|
151
|
-
import React from 'react';
|
|
152
|
-
|
|
153
|
-
function Component() {
|
|
154
|
-
return <h1>HELLO WORLD</h1>;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const config: RouteConfig = {
|
|
158
|
-
pattern: '/thanks2',
|
|
159
|
-
component: Component,
|
|
160
|
-
generateMetadata: () => ({ title: 'HightJS | Thanks' })
|
|
161
|
-
};
|
|
162
|
-
export default config;
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### Rotas Dinâmicas com Parâmetros
|
|
118
|
+
Documentação completa disponível na pasta `docs/`:
|
|
166
119
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
function PostPage({ params }: { params: { id: string } }) {
|
|
172
|
-
const id = params.id
|
|
173
|
-
return (
|
|
174
|
-
<div>
|
|
175
|
-
<h1>Post ID: {id}</h1>
|
|
176
|
-
<p>This is the content of post {id}.</p>
|
|
177
|
-
</div>
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const config: RouteConfig = {
|
|
182
|
-
pattern: '/post/[id]',
|
|
183
|
-
component: PostPage,
|
|
184
|
-
generateMetadata: async (params) => ({ title: `Post ${params.id}` })
|
|
185
|
-
};
|
|
186
|
-
export default config
|
|
187
|
-
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
### Layout Global
|
|
191
|
-
|
|
192
|
-
`src/web/layout.tsx`:
|
|
193
|
-
|
|
194
|
-
```tsx
|
|
195
|
-
export const metadata = { title: 'Meu App', description: 'Descrição global' };
|
|
196
|
-
export default function Layout({ children }: { children: React.ReactNode }) {
|
|
197
|
-
return <div>{children}</div>;
|
|
198
|
-
}
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### Página 404
|
|
202
|
-
|
|
203
|
-
`src/web/notFound.tsx`:
|
|
204
|
-
|
|
205
|
-
```tsx
|
|
206
|
-
export default function NotFound() {
|
|
207
|
-
return <h1>Página não encontrada</h1>;
|
|
208
|
-
}
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
---
|
|
120
|
+
### Fundamentos
|
|
121
|
+
- [📦 Estrutura Recomendada](./docs/estrutura.md)
|
|
122
|
+
- [🖥️ Rotas Frontend](./docs/rotas-frontend.md)
|
|
123
|
+
- [🌐 Rotas Backend](./docs/rotas-backend.md)
|
|
212
124
|
|
|
213
|
-
|
|
125
|
+
### Recursos Avançados
|
|
126
|
+
- [🛜 WebSocket](./docs/websocket.md)
|
|
127
|
+
- [🧩 Middlewares](./docs/middlewares.md)
|
|
128
|
+
- [🔐 Autenticação](./docs/autenticacao.md)
|
|
214
129
|
|
|
215
|
-
|
|
216
|
-
|
|
130
|
+
### Ferramentas e Configuração
|
|
131
|
+
- [🛠️ CLI](./docs/cli.md)
|
|
132
|
+
- [📂 Arquivos Especiais](./docs/arquivos-especiais.md)
|
|
133
|
+
- [🧱 Adapters](./docs/adapters.md)
|
|
134
|
+
- [🔐 Segurança Interna](./docs/seguranca.md)
|
|
135
|
+
- [♻️ Hot Reload](./docs/hot-reload.md)
|
|
217
136
|
|
|
218
|
-
###
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
```ts
|
|
223
|
-
import { HightJSRequest, HightJSResponse, BackendRouteConfig } from 'hightjs';
|
|
224
|
-
|
|
225
|
-
const route: BackendRouteConfig = {
|
|
226
|
-
pattern: '/version',
|
|
227
|
-
GET: async (_req: HightJSRequest) => {
|
|
228
|
-
return HightJSResponse.json({
|
|
229
|
-
version: '1.0.0',
|
|
230
|
-
name: 'HightJS',
|
|
231
|
-
description: 'Framework web full-stack moderno para Node.js'
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
};
|
|
235
|
-
export default route;
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### Suporte a Métodos
|
|
239
|
-
|
|
240
|
-
Defina `GET`, `POST`, `PUT`, `DELETE` (ou só os necessários).
|
|
241
|
-
|
|
242
|
-
### Rotas Dinâmicas Backend
|
|
243
|
-
|
|
244
|
-
`src/web/backend/routes/users/[id].ts` → `/users/123`
|
|
245
|
-
|
|
246
|
-
```ts
|
|
247
|
-
import { BackendRouteConfig, HightJSResponse } from "hightjs";
|
|
248
|
-
|
|
249
|
-
const route: BackendRouteConfig = {
|
|
250
|
-
pattern: '/users/[id]',
|
|
251
|
-
GET: async (req, params) => {
|
|
252
|
-
return HightJSResponse.json({ userId: params.id });
|
|
253
|
-
}
|
|
254
|
-
};
|
|
255
|
-
export default route;
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
---
|
|
259
|
-
|
|
260
|
-
## 🧩 Middlewares
|
|
261
|
-
|
|
262
|
-
Adicione middlewares:
|
|
263
|
-
|
|
264
|
-
- Direto na rota: `middleware: [...]`
|
|
265
|
-
- Arquivo `middleware.ts` na pasta (auto-carregado)
|
|
266
|
-
|
|
267
|
-
### Interface
|
|
268
|
-
|
|
269
|
-
```ts
|
|
270
|
-
export type HightMiddleware = (
|
|
271
|
-
request: HightJSRequest,
|
|
272
|
-
params: { [key: string]: string },
|
|
273
|
-
next: () => Promise<HightJSResponse>
|
|
274
|
-
) => Promise<HightJSResponse> | HightJSResponse;
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
### Exemplo por Pasta
|
|
278
|
-
|
|
279
|
-
`src/web/backend/routes/middleware.ts`:
|
|
280
|
-
|
|
281
|
-
```ts
|
|
282
|
-
import {HightJSRequest, HightJSResponse} from 'hightjs';
|
|
283
|
-
|
|
284
|
-
export async function log(
|
|
285
|
-
request: HightJSRequest,
|
|
286
|
-
params: { [key: string]: string },
|
|
287
|
-
next: () => Promise<HightJSResponse>
|
|
288
|
-
): Promise<HightJSResponse> {
|
|
289
|
-
|
|
290
|
-
console.log('[API]', request.method, request.url);
|
|
291
|
-
return next();
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
export async function blockLegacy(
|
|
296
|
-
request: HightJSRequest,
|
|
297
|
-
params: { [key: string]: string },
|
|
298
|
-
next: () => Promise<HightJSResponse>
|
|
299
|
-
): Promise<HightJSResponse> {
|
|
300
|
-
if (request.header('user-agent')?.includes('IE 8')) {
|
|
301
|
-
return HightJSResponse.json({ error: 'Navegador não suportado' }, {status: 400});
|
|
302
|
-
}
|
|
303
|
-
return next();
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
export default [log, blockLegacy];
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
### Exemplo por Rota
|
|
310
|
-
|
|
311
|
-
```ts
|
|
312
|
-
import {BackendRouteConfig, HightJSRequest, HightJSResponse} from 'hightjs';
|
|
313
|
-
|
|
314
|
-
async function authCheck(
|
|
315
|
-
request: HightJSRequest,
|
|
316
|
-
params: { [key: string]: string },
|
|
317
|
-
next: () => Promise<HightJSResponse>
|
|
318
|
-
): Promise<HightJSResponse> {
|
|
319
|
-
if(!request.header("authorization")) {
|
|
320
|
-
return HightJSResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
321
|
-
}
|
|
322
|
-
return next();
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
const route: BackendRouteConfig = {
|
|
326
|
-
pattern: '/secure/data',
|
|
327
|
-
middleware: [authCheck],
|
|
328
|
-
GET: async () => HightJSResponse.json({ secret: true })
|
|
329
|
-
};
|
|
330
|
-
export default route;
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
---
|
|
334
|
-
|
|
335
|
-
## 🔐 Autenticação (HightJS/auth)
|
|
336
|
-
|
|
337
|
-
Autenticação JWT embutida, fácil de configurar.
|
|
338
|
-
O jeito recomendado é criar as rotas diretamente no `auth.ts` e importar onde quiser.
|
|
339
|
-
|
|
340
|
-
### Configuração Básica & Rotas
|
|
341
|
-
|
|
342
|
-
`src/auth.ts`:
|
|
343
|
-
|
|
344
|
-
```ts
|
|
345
|
-
import { CredentialsProvider, DiscordProvider, createAuthRoutes } from 'hightjs/auth';
|
|
346
|
-
import type { AuthConfig } from 'hightjs/auth';
|
|
347
|
-
|
|
348
|
-
export const authConfig: AuthConfig = {
|
|
349
|
-
providers: [
|
|
350
|
-
new CredentialsProvider({
|
|
351
|
-
id: 'credentials',
|
|
352
|
-
name: 'Credentials',
|
|
353
|
-
credentials: {
|
|
354
|
-
username: { label: 'Username', type: 'text', placeholder: 'Digite seu usuário' },
|
|
355
|
-
password: { label: 'Password', type: 'password', placeholder: 'Digite sua senha' }
|
|
356
|
-
},
|
|
357
|
-
async authorize(credentials) {
|
|
358
|
-
if (credentials.username === 'admin' && credentials.password === 'admin') {
|
|
359
|
-
return {
|
|
360
|
-
id: '1',
|
|
361
|
-
username: 'admin',
|
|
362
|
-
email: 'admin@test.com',
|
|
363
|
-
name: 'Administrador',
|
|
364
|
-
testeeee: 'sdondsfndsfndsfodsfo'
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
return null;
|
|
368
|
-
}
|
|
369
|
-
}),
|
|
370
|
-
new DiscordProvider({
|
|
371
|
-
clientId: "ID",
|
|
372
|
-
clientSecret: "TOKEN",
|
|
373
|
-
callbackUrl: "http://localhost:3000/api/auth/callback/discord",
|
|
374
|
-
scope: ['identify', 'email', 'guilds'],
|
|
375
|
-
successUrl: "http://localhost:3000/"
|
|
376
|
-
})
|
|
377
|
-
],
|
|
378
|
-
session: {
|
|
379
|
-
strategy: 'jwt',
|
|
380
|
-
maxAge: 24 * 60 * 60, // 24 horas
|
|
381
|
-
},
|
|
382
|
-
pages: {
|
|
383
|
-
signIn: '/login',
|
|
384
|
-
signOut: '/'
|
|
385
|
-
},
|
|
386
|
-
secret: 'hweb-test-secret-key-change-in-production'
|
|
387
|
-
};
|
|
388
|
-
|
|
389
|
-
// Cria as rotas de autenticação automaticamente
|
|
390
|
-
export const authRoutes = createAuthRoutes(authConfig);
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
### Exportando as rotas
|
|
394
|
-
|
|
395
|
-
`src/web/backend/routes/auth.ts`:
|
|
396
|
-
|
|
397
|
-
```ts
|
|
398
|
-
import { authRoutes } from "../../../auth";
|
|
399
|
-
export default authRoutes;
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
### Configurando o Frontend
|
|
403
|
-
|
|
404
|
-
Para usar autenticação no frontend, você precisa configurar o `SessionProvider` no layout:
|
|
405
|
-
|
|
406
|
-
`src/web/layout.tsx`:
|
|
407
|
-
|
|
408
|
-
```tsx
|
|
409
|
-
import { SessionProvider } from 'hightjs/auth/react';
|
|
410
|
-
|
|
411
|
-
export const metadata = { title: 'Meu App', description: 'Descrição global' };
|
|
412
|
-
|
|
413
|
-
export default function Layout({ children }: { children: React.ReactNode }) {
|
|
414
|
-
return (
|
|
415
|
-
<SessionProvider>
|
|
416
|
-
{children}
|
|
417
|
-
</SessionProvider>
|
|
418
|
-
);
|
|
419
|
-
}
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
### Fazendo Login no Frontend
|
|
423
|
-
|
|
424
|
-
Exemplo de como implementar login com credenciais e Discord:
|
|
425
|
-
|
|
426
|
-
```tsx
|
|
427
|
-
import { useSession } from 'hightjs/auth/react';
|
|
428
|
-
import React, { useState } from 'react';
|
|
429
|
-
|
|
430
|
-
function LoginPage() {
|
|
431
|
-
const { signIn } = useSession();
|
|
432
|
-
const [username, setUsername] = useState('');
|
|
433
|
-
const [password, setPassword] = useState('');
|
|
434
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
435
|
-
const [error, setError] = useState<string | null>(null);
|
|
436
|
-
|
|
437
|
-
const handleDiscordLogin = async () => {
|
|
438
|
-
await signIn('discord', { redirect: true });
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
const handleLogin = async (e: React.FormEvent) => {
|
|
442
|
-
e.preventDefault();
|
|
443
|
-
setIsLoading(true);
|
|
444
|
-
setError(null);
|
|
445
|
-
|
|
446
|
-
try {
|
|
447
|
-
const result = await signIn('credentials', {
|
|
448
|
-
username: username,
|
|
449
|
-
password: password,
|
|
450
|
-
callbackUrl: '/'
|
|
451
|
-
});
|
|
452
|
-
|
|
453
|
-
if (!result || result.error) {
|
|
454
|
-
setError('Credenciais inválidas. Verifique seus dados e senha.');
|
|
455
|
-
setIsLoading(false);
|
|
456
|
-
return;
|
|
457
|
-
}
|
|
458
|
-
router.push("/")
|
|
459
|
-
} catch (err) {
|
|
460
|
-
setError('Ocorreu um erro inesperado. Tente novamente.');
|
|
461
|
-
setIsLoading(false);
|
|
462
|
-
}
|
|
463
|
-
};
|
|
464
|
-
|
|
465
|
-
return (
|
|
466
|
-
<div>
|
|
467
|
-
<form onSubmit={handleLogin}>
|
|
468
|
-
<input
|
|
469
|
-
type="text"
|
|
470
|
-
value={username}
|
|
471
|
-
onChange={(e) => setUsername(e.target.value)}
|
|
472
|
-
placeholder="Username"
|
|
473
|
-
/>
|
|
474
|
-
<input
|
|
475
|
-
type="password"
|
|
476
|
-
value={password}
|
|
477
|
-
onChange={(e) => setPassword(e.target.value)}
|
|
478
|
-
placeholder="Password"
|
|
479
|
-
/>
|
|
480
|
-
<button type="submit" disabled={isLoading}>Login</button>
|
|
481
|
-
</form>
|
|
482
|
-
|
|
483
|
-
<button onClick={handleDiscordLogin}>Login com Discord</button>
|
|
484
|
-
|
|
485
|
-
{error && <p style={{color: 'red'}}>{error}</p>}
|
|
486
|
-
</div>
|
|
487
|
-
);
|
|
488
|
-
}
|
|
489
|
-
```
|
|
490
|
-
|
|
491
|
-
### Acessando Dados do Usuário
|
|
492
|
-
|
|
493
|
-
Para acessar informações do usuário autenticado:
|
|
494
|
-
|
|
495
|
-
```tsx
|
|
496
|
-
import { useSession } from 'hightjs/auth/react';
|
|
497
|
-
|
|
498
|
-
function UserProfile() {
|
|
499
|
-
const { data: session, status, signOut } = useSession();
|
|
500
|
-
|
|
501
|
-
if (status === 'loading') return <p>Carregando...</p>;
|
|
502
|
-
|
|
503
|
-
if (!session) return <p>Não autenticado</p>;
|
|
504
|
-
|
|
505
|
-
return (
|
|
506
|
-
<div>
|
|
507
|
-
<h1>Bem-vindo, {session.user?.name}</h1>
|
|
508
|
-
<p>Email: {session.user?.email}</p>
|
|
509
|
-
<button onClick={() => signOut()}>Logout</button>
|
|
510
|
-
</div>
|
|
511
|
-
);
|
|
512
|
-
}
|
|
513
|
-
```
|
|
514
|
-
|
|
515
|
-
### Protegendo rotas backend
|
|
516
|
-
|
|
517
|
-
```ts
|
|
518
|
-
import { HightJSRequest } from "hightjs";
|
|
519
|
-
import { BackendRouteConfig, HightJSResponse } from "hightjs";
|
|
520
|
-
import { authRoutes } from "../../../../auth";
|
|
521
|
-
|
|
522
|
-
const route: BackendRouteConfig = {
|
|
523
|
-
pattern: "/api/version",
|
|
524
|
-
GET: async (req: HightJSRequest, params: any) => {
|
|
525
|
-
const session = await authRoutes.auth.getSession(req)
|
|
526
|
-
if (!session) {
|
|
527
|
-
return HightJSResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
528
|
-
}
|
|
529
|
-
return HightJSResponse.json({
|
|
530
|
-
version: "1.0.0",
|
|
531
|
-
name: "HightJS",
|
|
532
|
-
description: "Um framework web full-stack moderno para Node.js",
|
|
533
|
-
});
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
export default route;
|
|
537
|
-
```
|
|
538
|
-
|
|
539
|
-
### Métodos principais
|
|
540
|
-
|
|
541
|
-
- `signIn()` - Fazer login (credenciais ou provider)
|
|
542
|
-
- `signOut()` - Fazer logout
|
|
543
|
-
- `useSession()` - Hook para acessar sessão no frontend
|
|
544
|
-
- `authRoutes.auth.getSession()` - Verificar sessão no backend
|
|
545
|
-
- `authRoutes.auth.isAuthenticated()` - Verificar se está autenticado
|
|
546
|
-
|
|
547
|
-
---
|
|
548
|
-
|
|
549
|
-
## 🛠️ CLI
|
|
550
|
-
|
|
551
|
-
Comandos principais:
|
|
552
|
-
|
|
553
|
-
| Comando | Descrição |
|
|
554
|
-
|--------------------|-------------------------------------------|
|
|
555
|
-
| `npx hight dev` | Modo desenvolvimento (hot reload) |
|
|
556
|
-
| `npx hight start` | Modo produção (usa build gerado) |
|
|
557
|
-
|
|
558
|
-
### Opções
|
|
559
|
-
|
|
560
|
-
- `--port` Porta (default 3000)
|
|
561
|
-
- `--hostname` Host (default 0.0.0.0)
|
|
562
|
-
- `--framework` `native` | `express` | `fastify` (default: native)
|
|
563
|
-
|
|
564
|
-
### Produção
|
|
565
|
-
|
|
566
|
-
```bash
|
|
567
|
-
npx hight start -p 8080
|
|
568
|
-
```
|
|
569
|
-
|
|
570
|
-
---
|
|
571
|
-
|
|
572
|
-
## 📂 Arquivos Especiais
|
|
573
|
-
|
|
574
|
-
| Arquivo | Localização | Função |
|
|
575
|
-
|-----------------------------|---------------------------------------|------------------------------------------------|
|
|
576
|
-
| `layout.tsx` | `/src/web` | Layout global + `export const metadata` |
|
|
577
|
-
| `notFound.tsx` | `/src/web` | Página 404 customizada |
|
|
578
|
-
| `middleware.ts` | dentro de `/src/web/backend/routes` | Middlewares globais por pasta backend |
|
|
579
|
-
| `hightweb.ts` / `.tsx` | `/src/hightweb` | Instrumentação opcional executada no boot |
|
|
580
|
-
| `public/` | `/public` | Arquivos estáticos servidos diretamente |
|
|
581
|
-
|
|
582
|
-
---
|
|
583
|
-
|
|
584
|
-
## 🧱 Adapters
|
|
585
|
-
|
|
586
|
-
Inicie via: `--framework native|express|fastify`
|
|
587
|
-
|
|
588
|
-
- Native: zero dependências extras
|
|
589
|
-
- Express/Fastify: instale peer deps (express ou fastify)
|
|
590
|
-
|
|
591
|
-
---
|
|
592
|
-
|
|
593
|
-
## 🔐 Segurança Interna
|
|
594
|
-
|
|
595
|
-
- Sanitização de headers, cookies e body
|
|
596
|
-
- Limites de tamanho configuráveis
|
|
597
|
-
- Proteção contra JSON malformado
|
|
598
|
-
- Timeout de requisição / body parser nativo
|
|
599
|
-
- JWT com HS256, verificação constant-time
|
|
600
|
-
|
|
601
|
-
---
|
|
602
|
-
|
|
603
|
-
## ♻️ Hot Reload
|
|
604
|
-
|
|
605
|
-
Em modo dev, o cliente abre WebSocket `/hweb-hotreload/`.
|
|
606
|
-
Mudanças em rotas frontend ou backend recarregam automaticamente.
|
|
607
|
-
|
|
608
|
-
---
|
|
609
|
-
|
|
610
|
-
## ❓ FAQ Rápido
|
|
611
|
-
|
|
612
|
-
| Pergunta | Resposta |
|
|
613
|
-
|--------------------------------|-----------------------------------------------------|
|
|
614
|
-
| Precisa Next/Vite? | Não, bundler interno via esbuild. |
|
|
615
|
-
| Dá para usar React 19? | Sim (peer dependency). |
|
|
616
|
-
| Tem SSR? | Atualmente só client-side hydration. |
|
|
617
|
-
| Posso usar CSS/SCSS? | Import normal nos componentes. |
|
|
618
|
-
| Rota de API conflita com página?| Não, rotas backend podem ser qualquer path. |
|
|
619
|
-
|
|
620
|
-
---
|
|
621
|
-
|
|
622
|
-
## ✅ Checklist Mental
|
|
623
|
-
|
|
624
|
-
1. Precisa de página? Crie em `src/web/routes/...`
|
|
625
|
-
2. Precisa de endpoint? Crie em `src/web/backend/routes/...`
|
|
626
|
-
3. Precisa proteger? Use autenticação nas rotas
|
|
627
|
-
4. Precisa middleware? `middleware.ts` ou `middleware: []` na rota
|
|
628
|
-
5. Metadata? `generateMetadata` ou `metadata` no layout
|
|
629
|
-
6. Deploy? `npx hight start`
|
|
137
|
+
### Ajuda
|
|
138
|
+
- [❓ FAQ Rápido](./docs/faq.md)
|
|
139
|
+
- [✅ Checklist Mental](./docs/checklist.md)
|
|
630
140
|
|
|
631
141
|
---
|
|
632
142
|
|
|
@@ -638,3 +148,5 @@ Este projeto está licenciado sob a [Licença Apache 2.0](LICENSE).
|
|
|
638
148
|
|
|
639
149
|
---
|
|
640
150
|
|
|
151
|
+
|
|
152
|
+
|
package/dist/auth/core.js
CHANGED
|
@@ -55,7 +55,7 @@ class HWebAuth {
|
|
|
55
55
|
const sessionResult = this.sessionManager.createSession(user);
|
|
56
56
|
// Callback de sessão se definido
|
|
57
57
|
if (this.config.callbacks?.session) {
|
|
58
|
-
sessionResult.session = await this.config.callbacks.session(sessionResult.session, user);
|
|
58
|
+
sessionResult.session = await this.config.callbacks.session({ session: sessionResult.session, user, provider: providerId });
|
|
59
59
|
}
|
|
60
60
|
return sessionResult;
|
|
61
61
|
}
|
|
@@ -86,7 +86,7 @@ class HWebAuth {
|
|
|
86
86
|
.clearCookie('hweb-auth-token', {
|
|
87
87
|
path: '/',
|
|
88
88
|
httpOnly: true,
|
|
89
|
-
secure:
|
|
89
|
+
secure: this.config.secureCookies || false,
|
|
90
90
|
sameSite: 'strict'
|
|
91
91
|
});
|
|
92
92
|
}
|
|
@@ -143,7 +143,7 @@ class HWebAuth {
|
|
|
143
143
|
.json(data)
|
|
144
144
|
.cookie('hweb-auth-token', token, {
|
|
145
145
|
httpOnly: true,
|
|
146
|
-
secure:
|
|
146
|
+
secure: this.config.secureCookies || false, // Always secure, even in development
|
|
147
147
|
sameSite: 'strict', // Prevent CSRF attacks
|
|
148
148
|
maxAge: (this.config.session?.maxAge || 86400) * 1000,
|
|
149
149
|
path: '/',
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -3,5 +3,5 @@ export * from './providers';
|
|
|
3
3
|
export * from './core';
|
|
4
4
|
export * from './routes';
|
|
5
5
|
export * from './jwt';
|
|
6
|
-
export { CredentialsProvider, DiscordProvider } from './providers';
|
|
6
|
+
export { CredentialsProvider, DiscordProvider, GoogleProvider } from './providers';
|
|
7
7
|
export { createAuthRoutes } from './routes';
|
package/dist/auth/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.createAuthRoutes = exports.DiscordProvider = exports.CredentialsProvider = void 0;
|
|
17
|
+
exports.createAuthRoutes = exports.GoogleProvider = exports.DiscordProvider = exports.CredentialsProvider = void 0;
|
|
18
18
|
// Exportações principais do sistema de autenticação
|
|
19
19
|
__exportStar(require("./types"), exports);
|
|
20
20
|
__exportStar(require("./providers"), exports);
|
|
@@ -24,5 +24,6 @@ __exportStar(require("./jwt"), exports);
|
|
|
24
24
|
var providers_1 = require("./providers");
|
|
25
25
|
Object.defineProperty(exports, "CredentialsProvider", { enumerable: true, get: function () { return providers_1.CredentialsProvider; } });
|
|
26
26
|
Object.defineProperty(exports, "DiscordProvider", { enumerable: true, get: function () { return providers_1.DiscordProvider; } });
|
|
27
|
+
Object.defineProperty(exports, "GoogleProvider", { enumerable: true, get: function () { return providers_1.GoogleProvider; } });
|
|
27
28
|
var routes_1 = require("./routes");
|
|
28
29
|
Object.defineProperty(exports, "createAuthRoutes", { enumerable: true, get: function () { return routes_1.createAuthRoutes; } });
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { AuthProviderClass, AuthRoute, User } from '../types';
|
|
2
|
+
export interface GoogleConfig {
|
|
3
|
+
id?: string;
|
|
4
|
+
name?: string;
|
|
5
|
+
clientId: string;
|
|
6
|
+
clientSecret: string;
|
|
7
|
+
callbackUrl?: string;
|
|
8
|
+
successUrl?: string;
|
|
9
|
+
scope?: string[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Provider para autenticação com Google OAuth2
|
|
13
|
+
*
|
|
14
|
+
* Este provider permite autenticação usando Google OAuth2.
|
|
15
|
+
* Automaticamente gerencia o fluxo OAuth completo e rotas necessárias.
|
|
16
|
+
*
|
|
17
|
+
* Exemplo de uso:
|
|
18
|
+
* ```typescript
|
|
19
|
+
* new GoogleProvider({
|
|
20
|
+
* clientId: process.env.GOOGLE_CLIENT_ID!,
|
|
21
|
+
* clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
|
|
22
|
+
* callbackUrl: "http://localhost:3000/api/auth/callback/google"
|
|
23
|
+
* })
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* Fluxo de autenticação:
|
|
27
|
+
* 1. GET /api/auth/signin/google - Gera URL e redireciona para Google
|
|
28
|
+
* 2. Google redireciona para /api/auth/callback/google com código
|
|
29
|
+
* 3. Provider troca código por token e busca dados do usuário
|
|
30
|
+
* 4. Retorna objeto User com dados do Google
|
|
31
|
+
*/
|
|
32
|
+
export declare class GoogleProvider implements AuthProviderClass {
|
|
33
|
+
readonly id: string;
|
|
34
|
+
readonly name: string;
|
|
35
|
+
readonly type: string;
|
|
36
|
+
private config;
|
|
37
|
+
private readonly defaultScope;
|
|
38
|
+
constructor(config: GoogleConfig);
|
|
39
|
+
/**
|
|
40
|
+
* Método para gerar URL OAuth (usado pelo handleSignIn)
|
|
41
|
+
*/
|
|
42
|
+
handleOauth(credentials?: Record<string, string>): string;
|
|
43
|
+
/**
|
|
44
|
+
* Método principal - redireciona para OAuth ou processa o callback
|
|
45
|
+
*/
|
|
46
|
+
handleSignIn(credentials: Record<string, string>): Promise<User | string | null>;
|
|
47
|
+
/**
|
|
48
|
+
* Processa o callback do OAuth (troca o código pelo usuário)
|
|
49
|
+
*/
|
|
50
|
+
private processOAuthCallback;
|
|
51
|
+
/**
|
|
52
|
+
* Rotas adicionais específicas do Google OAuth
|
|
53
|
+
*/
|
|
54
|
+
additionalRoutes: AuthRoute[];
|
|
55
|
+
/**
|
|
56
|
+
* Gera a URL de autorização do Google
|
|
57
|
+
*/
|
|
58
|
+
getAuthorizationUrl(): string;
|
|
59
|
+
/**
|
|
60
|
+
* Retorna a configuração pública do provider
|
|
61
|
+
*/
|
|
62
|
+
getConfig(): any;
|
|
63
|
+
}
|