hightjs 0.4.0 → 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 (125) hide show
  1. package/README.md +48 -116
  2. package/dist/bin/hightjs.js +51 -23
  3. package/dist/builder.js +139 -4
  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 +39 -29
  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 +2 -2
  13. package/dist/index.js +16 -16
  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 +36 -31
  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/backend/auth.ts +0 -42
  81. package/example/src/backend/routes/auth.ts +0 -3
  82. package/example/src/backend/routes/version.ts +0 -13
  83. package/example/src/web/components/Home.tsx +0 -140
  84. package/example/src/web/components/LoginPage.tsx +0 -149
  85. package/example/src/web/globals.css +0 -5
  86. package/example/src/web/layout.tsx +0 -100
  87. package/example/src/web/routes/index.tsx +0 -13
  88. package/example/src/web/routes/login.tsx +0 -30
  89. package/example/tailwind.config.js +0 -12
  90. package/example/tsconfig.json +0 -15
  91. package/src/adapters/express.ts +0 -87
  92. package/src/adapters/factory.ts +0 -112
  93. package/src/adapters/fastify.ts +0 -104
  94. package/src/adapters/native.ts +0 -234
  95. package/src/api/console.ts +0 -305
  96. package/src/api/http.ts +0 -535
  97. package/src/auth/client.ts +0 -171
  98. package/src/auth/components.tsx +0 -125
  99. package/src/auth/core.ts +0 -215
  100. package/src/auth/index.ts +0 -25
  101. package/src/auth/jwt.ts +0 -210
  102. package/src/auth/providers/credentials.ts +0 -139
  103. package/src/auth/providers/discord.ts +0 -239
  104. package/src/auth/providers/google.ts +0 -234
  105. package/src/auth/providers/index.ts +0 -20
  106. package/src/auth/providers.ts +0 -20
  107. package/src/auth/react/index.ts +0 -25
  108. package/src/auth/react.tsx +0 -234
  109. package/src/auth/routes.ts +0 -183
  110. package/src/auth/types.ts +0 -108
  111. package/src/bin/hightjs.js +0 -222
  112. package/src/builder.js +0 -472
  113. package/src/client/DefaultNotFound.tsx +0 -84
  114. package/src/client/clientRouter.ts +0 -153
  115. package/src/client/entry.client.tsx +0 -511
  116. package/src/client.ts +0 -24
  117. package/src/components/Link.tsx +0 -38
  118. package/src/helpers.ts +0 -542
  119. package/src/hotReload.ts +0 -569
  120. package/src/index.ts +0 -555
  121. package/src/renderer.tsx +0 -263
  122. package/src/router.ts +0 -730
  123. package/src/types/framework.ts +0 -58
  124. package/src/types.ts +0 -207
  125. package/tsconfig.json +0 -17
package/src/api/http.ts DELETED
@@ -1,535 +0,0 @@
1
- /*
2
- * This file is part of the HightJS Project.
3
- * Copyright (c) 2025 itsmuzin
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * http://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
- import { GenericRequest, GenericResponse, CookieOptions } from '../types/framework';
18
-
19
- // Input validation and sanitization utilities
20
- class SecurityUtils {
21
- static readonly MAX_HEADER_LENGTH = 8192;
22
- static readonly MAX_COOKIE_LENGTH = 4096;
23
- static readonly MAX_URL_LENGTH = 2048;
24
- static readonly MAX_BODY_SIZE = 10 * 1024 * 1024; // 10MB
25
-
26
- static sanitizeHeader(value: string | string[]): string | string[] {
27
- if (Array.isArray(value)) {
28
- return value.map(v => this.sanitizeString(v, this.MAX_HEADER_LENGTH));
29
- }
30
- return this.sanitizeString(value, this.MAX_HEADER_LENGTH);
31
- }
32
-
33
- static sanitizeString(str: string, maxLength: number): string {
34
- if (typeof str !== 'string') return '';
35
-
36
- // Remove null bytes and control characters except newline/tab
37
- let clean = str.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '');
38
-
39
- // Limit length
40
- if (clean.length > maxLength) {
41
- clean = clean.substring(0, maxLength);
42
- }
43
-
44
- return clean;
45
- }
46
-
47
- static isValidURL(url: string): boolean {
48
- if (!url || typeof url !== 'string') return false;
49
- if (url.length > this.MAX_URL_LENGTH) return false;
50
-
51
- // Basic URL validation - prevent dangerous protocols
52
- const dangerousProtocols = ['javascript:', 'data:', 'vbscript:', 'file:'];
53
- const lowerUrl = url.toLowerCase();
54
-
55
- return !dangerousProtocols.some(protocol => lowerUrl.startsWith(protocol));
56
- }
57
-
58
- static validateContentLength(length: number): boolean {
59
- return length >= 0 && length <= this.MAX_BODY_SIZE;
60
- }
61
- }
62
-
63
- /**
64
- * Abstração sobre a requisição HTTP de entrada.
65
- * Funciona com qualquer framework web (Express, Fastify, etc.)
66
- */
67
- export class HightJSRequest {
68
- /** A requisição genérica parseada pelo adapter */
69
- private readonly _req: GenericRequest;
70
-
71
- constructor(req: GenericRequest) {
72
- // Validate and sanitize request data
73
- this._req = this.validateAndSanitizeRequest(req);
74
- }
75
-
76
- private validateAndSanitizeRequest(req: GenericRequest): GenericRequest {
77
- // Validate URL
78
- if (!SecurityUtils.isValidURL(req.url)) {
79
- throw new Error('Invalid URL format');
80
- }
81
-
82
- // Sanitize headers
83
- const sanitizedHeaders: Record<string, string | string[]> = {};
84
- for (const [key, value] of Object.entries(req.headers || {})) {
85
- const cleanKey = SecurityUtils.sanitizeString(key.toLowerCase(), 100);
86
- if (cleanKey && value) {
87
- sanitizedHeaders[cleanKey] = SecurityUtils.sanitizeHeader(value);
88
- }
89
- }
90
-
91
- // Validate content length
92
- const contentLength = req.headers['content-length'];
93
- if (contentLength) {
94
- const length = parseInt(Array.isArray(contentLength) ? contentLength[0] : contentLength, 10);
95
- if (!SecurityUtils.validateContentLength(length)) {
96
- throw new Error('Request too large');
97
- }
98
- }
99
-
100
- // Sanitize cookies
101
- const sanitizedCookies: Record<string, string> = {};
102
- for (const [key, value] of Object.entries(req.cookies || {})) {
103
- const cleanKey = SecurityUtils.sanitizeString(key, 100);
104
- const cleanValue = SecurityUtils.sanitizeString(value, SecurityUtils.MAX_COOKIE_LENGTH);
105
- if (cleanKey && cleanValue) {
106
- sanitizedCookies[cleanKey] = cleanValue;
107
- }
108
- }
109
-
110
- return {
111
- ...req,
112
- headers: sanitizedHeaders,
113
- cookies: sanitizedCookies,
114
- url: SecurityUtils.sanitizeString(req.url, SecurityUtils.MAX_URL_LENGTH)
115
- };
116
- }
117
-
118
- /**
119
- * Retorna o método HTTP da requisição (GET, POST, etc.)
120
- */
121
- get method(): string {
122
- return this._req.method;
123
- }
124
-
125
- /**
126
- * Retorna a URL completa da requisição
127
- */
128
- get url(): string {
129
- return this._req.url;
130
- }
131
-
132
- /**
133
- * Retorna todos os headers da requisição
134
- */
135
- get headers(): Record<string, string | string[]> {
136
- return this._req.headers;
137
- }
138
-
139
- /**
140
- * Retorna um header específico com validação
141
- */
142
- header(name: string): string | string[] | undefined {
143
- if (!name || typeof name !== 'string') return undefined;
144
- const cleanName = SecurityUtils.sanitizeString(name.toLowerCase(), 100);
145
- return this._req.headers[cleanName];
146
- }
147
-
148
- /**
149
- * Retorna todos os query parameters
150
- */
151
- get query(): Record<string, any> {
152
- return this._req.query || {};
153
- }
154
-
155
- /**
156
- * Retorna todos os parâmetros de rota
157
- */
158
- get params(): Record<string, string> {
159
- return this._req.params || {};
160
- }
161
-
162
- /**
163
- * Retorna todos os cookies
164
- */
165
- get cookies(): Record<string, string> {
166
- return this._req.cookies || {};
167
- }
168
-
169
- /**
170
- * Retorna um cookie específico com validação
171
- */
172
- cookie(name: string): string | undefined {
173
- if (!name || typeof name !== 'string') return undefined;
174
- const cleanName = SecurityUtils.sanitizeString(name, 100);
175
- return this._req.cookies?.[cleanName];
176
- }
177
-
178
- /**
179
- * Retorna o corpo (body) da requisição, já parseado como JSON com validação
180
- */
181
- async json<T = any>(): Promise<T> {
182
- try {
183
- const body = this._req.body;
184
-
185
- // Validate JSON structure
186
- if (typeof body === 'string') {
187
- // Check for potential JSON bombs
188
- if (body.length > SecurityUtils.MAX_BODY_SIZE) {
189
- throw new Error('Request body too large');
190
- }
191
- return JSON.parse(body);
192
- }
193
-
194
- return body;
195
- } catch (error) {
196
- if (error instanceof SyntaxError) {
197
- throw new Error('Invalid JSON format');
198
- }
199
- throw error;
200
- }
201
- }
202
-
203
- /**
204
- * Retorna o corpo da requisição como texto
205
- */
206
- async text(): Promise<string> {
207
- if (typeof this._req.body === 'string') {
208
- return this._req.body;
209
- }
210
- return JSON.stringify(this._req.body);
211
- }
212
-
213
- /**
214
- * Retorna o corpo da requisição como FormData (para uploads)
215
- */
216
- async formData(): Promise<any> {
217
- return this._req.body;
218
- }
219
-
220
- /**
221
- * Retorna a requisição original do framework
222
- */
223
- get raw(): any {
224
- return this._req.raw;
225
- }
226
-
227
- /**
228
- * Verifica se a requisição tem um content-type específico
229
- */
230
- is(type: string): boolean {
231
- const contentType = this.header('content-type');
232
- if (!contentType) return false;
233
-
234
- const ct = Array.isArray(contentType) ? contentType[0] : contentType;
235
- return ct.toLowerCase().includes(type.toLowerCase());
236
- }
237
-
238
- /**
239
- * Verifica se a requisição é AJAX/XHR
240
- */
241
- get isAjax(): boolean {
242
- const xhr = this.header('x-requested-with');
243
- return xhr === 'XMLHttpRequest';
244
- }
245
-
246
- /**
247
- * Retorna o IP do cliente com validação melhorada
248
- */
249
- get ip(): string {
250
- // Check X-Forwarded-For with validation
251
- const forwarded = this.header('x-forwarded-for');
252
- if (forwarded) {
253
- const ips = Array.isArray(forwarded) ? forwarded[0] : forwarded;
254
- const firstIp = ips.split(',')[0].trim();
255
-
256
- // Basic IP validation
257
- if (this.isValidIP(firstIp)) {
258
- return firstIp;
259
- }
260
- }
261
-
262
- // Check X-Real-IP
263
- const realIp = this.header('x-real-ip');
264
- if (realIp) {
265
- const ip = Array.isArray(realIp) ? realIp[0] : realIp;
266
- if (this.isValidIP(ip)) {
267
- return ip;
268
- }
269
- }
270
-
271
- return 'unknown';
272
- }
273
-
274
- private isValidIP(ip: string): boolean {
275
- if (!ip || typeof ip !== 'string') return false;
276
-
277
- // Basic IPv4 validation
278
- const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
279
- if (ipv4Regex.test(ip)) {
280
- const parts = ip.split('.');
281
- return parts.every(part => {
282
- const num = parseInt(part, 10);
283
- return num >= 0 && num <= 255;
284
- });
285
- }
286
-
287
- // Basic IPv6 validation (simplified)
288
- const ipv6Regex = /^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$/;
289
- return ipv6Regex.test(ip);
290
- }
291
-
292
- /**
293
- * Retorna o User-Agent
294
- */
295
- get userAgent(): string | undefined {
296
- const ua = this.header('user-agent');
297
- return Array.isArray(ua) ? ua[0] : ua;
298
- }
299
- }
300
-
301
- /**
302
- * Abstração para construir a resposta HTTP.
303
- * Funciona com qualquer framework web (Express, Fastify, etc.)
304
- */
305
- export class HightJSResponse {
306
- private _status: number = 200;
307
- private _headers: Record<string, string> = {};
308
- private _cookies: Array<{ name: string; value: string; options?: CookieOptions }> = [];
309
- private _body: any = null;
310
- private _sent: boolean = false;
311
-
312
- /**
313
- * Define o status HTTP da resposta
314
- */
315
- status(code: number): HightJSResponse {
316
- this._status = code;
317
- return this;
318
- }
319
-
320
- /**
321
- * Define um header da resposta
322
- */
323
- header(name: string, value: string): HightJSResponse {
324
- this._headers[name] = value;
325
- return this;
326
- }
327
-
328
- /**
329
- * Define múltiplos headers
330
- */
331
- headers(headers: Record<string, string>): HightJSResponse {
332
- Object.assign(this._headers, headers);
333
- return this;
334
- }
335
-
336
- /**
337
- * Define um cookie
338
- */
339
- cookie(name: string, value: string, options?: CookieOptions): HightJSResponse {
340
- this._cookies.push({ name, value, options });
341
- return this;
342
- }
343
-
344
- /**
345
- * Remove um cookie
346
- */
347
- clearCookie(name: string, options?: CookieOptions): HightJSResponse {
348
- this._cookies.push({
349
- name,
350
- value: '',
351
- options: { ...options, expires: new Date(0) }
352
- });
353
- return this;
354
- }
355
-
356
- /**
357
- * Envia resposta JSON
358
- */
359
- json(data: any): HightJSResponse {
360
- this._headers['Content-Type'] = 'application/json';
361
- this._body = JSON.stringify(data);
362
- this._sent = true;
363
- return this;
364
- }
365
-
366
- /**
367
- * Envia resposta de texto
368
- */
369
- text(data: string): HightJSResponse {
370
- this._headers['Content-Type'] = 'text/plain; charset=utf-8';
371
- this._body = data;
372
- this._sent = true;
373
- return this;
374
- }
375
-
376
- /**
377
- * Envia resposta HTML
378
- */
379
- html(data: string): HightJSResponse {
380
- this._headers['Content-Type'] = 'text/html; charset=utf-8';
381
- this._body = data;
382
- this._sent = true;
383
- return this;
384
- }
385
-
386
- /**
387
- * Envia qualquer tipo de dados
388
- */
389
- send(data: any): HightJSResponse {
390
- this._body = data;
391
- this._sent = true;
392
- return this;
393
- }
394
-
395
- /**
396
- * Redireciona para uma URL
397
- */
398
- redirect(url: string, status: number = 302): HightJSResponse {
399
- this._status = status;
400
- this._headers['Location'] = url;
401
- this._sent = true;
402
- return this;
403
- }
404
-
405
- /**
406
- * Método interno para aplicar a resposta ao objeto de resposta do framework
407
- */
408
- public _applyTo(res: GenericResponse): void {
409
- // Aplica status
410
- res.status(this._status);
411
-
412
- // Aplica headers
413
- Object.entries(this._headers).forEach(([name, value]) => {
414
- res.header(name, value);
415
- });
416
-
417
- // Aplica cookies
418
- this._cookies.forEach(({ name, value, options }) => {
419
- if (options?.expires && options.expires.getTime() === 0) {
420
- res.clearCookie(name, options);
421
- } else {
422
- res.cookie(name, value, options);
423
- }
424
- });
425
-
426
- // Handle redirects specifically
427
- if (this._headers['Location']) {
428
- res.redirect(this._headers['Location']);
429
- return;
430
- }
431
-
432
- // Envia o corpo se foi definido
433
- if (this._sent && this._body !== null) {
434
- if (this._headers['Content-Type']?.includes('application/json')) {
435
- res.json(JSON.parse(this._body));
436
- } else {
437
- res.send(this._body);
438
- }
439
- }
440
- }
441
-
442
- /**
443
- * Método de compatibilidade com versão anterior (Express)
444
- */
445
- public _send(res: any): void {
446
- // Assume que é Express se tem os métodos específicos
447
- if (res.set && res.status && res.send) {
448
- res.set(this._headers).status(this._status);
449
-
450
- this._cookies.forEach(({ name, value, options }) => {
451
- if (options?.expires && options.expires.getTime() === 0) {
452
- res.clearCookie(name, options);
453
- } else {
454
- res.cookie(name, value, options);
455
- }
456
- });
457
-
458
- res.send(this._body);
459
- }
460
- }
461
-
462
- // === MÉTODOS ESTÁTICOS DE CONVENIÊNCIA ===
463
-
464
- /**
465
- * Cria uma resposta JSON
466
- */
467
- static json(data: any, options?: { status?: number, headers?: Record<string, string> }): HightJSResponse {
468
- const response = new HightJSResponse();
469
- if (options?.status) response.status(options.status);
470
- if (options?.headers) response.headers(options.headers);
471
- return response.json(data);
472
- }
473
-
474
- /**
475
- * Cria uma resposta de texto
476
- */
477
- static text(data: string, options?: { status?: number, headers?: Record<string, string> }): HightJSResponse {
478
- const response = new HightJSResponse();
479
- if (options?.status) response.status(options.status);
480
- if (options?.headers) response.headers(options.headers);
481
- return response.text(data);
482
- }
483
-
484
- /**
485
- * Cria uma resposta HTML
486
- */
487
- static html(data: string, options?: { status?: number, headers?: Record<string, string> }): HightJSResponse {
488
- const response = new HightJSResponse();
489
- if (options?.status) response.status(options.status);
490
- if (options?.headers) response.headers(options.headers);
491
- return response.html(data);
492
- }
493
-
494
- /**
495
- * Cria um redirecionamento
496
- */
497
- static redirect(url: string, status: number = 302): HightJSResponse {
498
- return new HightJSResponse().redirect(url, status);
499
- }
500
-
501
- /**
502
- * Cria uma resposta 404
503
- */
504
- static notFound(message: string = 'Not Found'): HightJSResponse {
505
- return HightJSResponse.text(message, { status: 404 });
506
- }
507
-
508
- /**
509
- * Cria uma resposta 500
510
- */
511
- static error(message: string = 'Internal Server Error'): HightJSResponse {
512
- return HightJSResponse.text(message, { status: 500 });
513
- }
514
-
515
- /**
516
- * Cria uma resposta 400
517
- */
518
- static badRequest(message: string = 'Bad Request'): HightJSResponse {
519
- return HightJSResponse.text(message, { status: 400 });
520
- }
521
-
522
- /**
523
- * Cria uma resposta 401
524
- */
525
- static unauthorized(message: string = 'Unauthorized'): HightJSResponse {
526
- return HightJSResponse.text(message, { status: 401 });
527
- }
528
-
529
- /**
530
- * Cria uma resposta 403
531
- */
532
- static forbidden(message: string = 'Forbidden'): HightJSResponse {
533
- return HightJSResponse.text(message, { status: 403 });
534
- }
535
- }
@@ -1,171 +0,0 @@
1
- /*
2
- * This file is part of the HightJS Project.
3
- * Copyright (c) 2025 itsmuzin
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * http://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
- import type { SignInOptions, SignInResult, Session } from './types';
18
- // Configuração global do client
19
- let basePath = '/api/auth';
20
-
21
- export function setBasePath(path: string) {
22
- basePath = path;
23
- }
24
-
25
- /**
26
- * Função para obter a sessão atual (similar ao NextAuth getSession)
27
- */
28
- export async function getSession(): Promise<Session | null> {
29
- try {
30
- const response = await fetch(`${basePath}/session`, {
31
- credentials: 'include'
32
- });
33
-
34
- if (!response.ok) {
35
- return null;
36
- }
37
-
38
- const data = await response.json();
39
- return data.session || null;
40
- } catch (error) {
41
- console.error('[hweb-auth] Error fetching session:', error);
42
- return null;
43
- }
44
- }
45
-
46
- /**
47
- * Função para obter token CSRF
48
- */
49
- export async function getCsrfToken(): Promise<string | null> {
50
- try {
51
- const response = await fetch(`${basePath}/csrf`, {
52
- credentials: 'include'
53
- });
54
-
55
- if (!response.ok) {
56
- return null;
57
- }
58
-
59
- const data = await response.json();
60
- return data.csrfToken || null;
61
- } catch (error) {
62
- console.error('[hweb-auth] Error fetching CSRF token:', error);
63
- return null;
64
- }
65
- }
66
-
67
- /**
68
- * Função para obter providers disponíveis
69
- */
70
- export async function getProviders(): Promise<any[] | null> {
71
- try {
72
- const response = await fetch(`${basePath}/providers`, {
73
- credentials: 'include'
74
- });
75
-
76
- if (!response.ok) {
77
- return null;
78
- }
79
-
80
- const data = await response.json();
81
- return data.providers || [];
82
- } catch (error) {
83
- console.error('[hweb-auth] Error searching for providers:', error);
84
- return null;
85
- }
86
- }
87
-
88
- /**
89
- * Função para fazer login (similar ao NextAuth signIn)
90
- */
91
- export async function signIn(
92
- provider: string = 'credentials',
93
- options: SignInOptions = {}
94
- ): Promise<SignInResult | undefined> {
95
- try {
96
- const { redirect = true, callbackUrl, ...credentials } = options;
97
-
98
- const response = await fetch(`${basePath}/signin`, {
99
- method: 'POST',
100
- headers: {
101
- 'Content-Type': 'application/json',
102
- },
103
- credentials: 'include',
104
- body: JSON.stringify({
105
- provider,
106
- ...credentials
107
- })
108
- });
109
-
110
- const data = await response.json();
111
-
112
- if (response.ok && data.success) {
113
- // Se é OAuth, redireciona para URL fornecida
114
- if (data.type === 'oauth' && data.redirectUrl) {
115
- if (redirect && typeof window !== 'undefined') {
116
- window.location.href = data.redirectUrl;
117
- }
118
-
119
- return {
120
- ok: true,
121
- status: 200,
122
- url: data.redirectUrl
123
- };
124
- }
125
-
126
- // Se é sessão (credentials), redireciona para callbackUrl
127
- if (data.type === 'session') {
128
- if (redirect && typeof window !== 'undefined') {
129
- window.location.href = callbackUrl || '/';
130
- }
131
-
132
- return {
133
- ok: true,
134
- status: 200,
135
- url: callbackUrl || '/'
136
- };
137
- }
138
- } else {
139
- return {
140
- error: data.error || 'Authentication failed',
141
- status: response.status,
142
- ok: false
143
- };
144
- }
145
- } catch (error) {
146
- console.error('[hweb-auth] Error on signIn:', error);
147
- return {
148
- error: 'Network error',
149
- status: 500,
150
- ok: false
151
- };
152
- }
153
- }
154
-
155
- /**
156
- * Função para fazer logout (similar ao NextAuth signOut)
157
- */
158
- export async function signOut(options: { callbackUrl?: string } = {}): Promise<void> {
159
- try {
160
- await fetch(`${basePath}/signout`, {
161
- method: 'POST',
162
- credentials: 'include'
163
- });
164
-
165
- if (typeof window !== 'undefined') {
166
- window.location.href = options.callbackUrl || '/';
167
- }
168
- } catch (error) {
169
- console.error('[hweb-auth] Error on signOut:', error);
170
- }
171
- }