@purecore/one-server-4-all 0.1.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.
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Um mini-validador type-safe inspirado no Zod.
3
+ * Garante que nossa configuração de entrada seja válida sem importar bibliotecas externas.
4
+ */
5
+
6
+ export class Schema<T> {
7
+ constructor(private validator: (value: unknown) => T) {}
8
+
9
+ parse(value: unknown): T {
10
+ return this.validator(value);
11
+ }
12
+ }
13
+
14
+ export const z = {
15
+ string: () => new Schema<string>((val) => {
16
+ if (typeof val !== 'string') throw new Error(`Expected string, received ${typeof val}`);
17
+ return val;
18
+ }),
19
+
20
+ number: () => new Schema<number>((val) => {
21
+ const num = Number(val);
22
+ if (isNaN(num)) throw new Error(`Expected number, received ${val}`);
23
+ return num;
24
+ }),
25
+
26
+ object: <T extends Record<string, Schema<any>>>(shape: T) => new Schema<{ [K in keyof T]: ReturnType<T[K]['parse']> }>((val) => {
27
+ if (typeof val !== 'object' || val === null) throw new Error("Expected object");
28
+ const result: any = {};
29
+ const obj = val as any;
30
+
31
+ for (const key in shape) {
32
+ try {
33
+ result[key] = shape[key].parse(obj[key]);
34
+ } catch (e: any) {
35
+ throw new Error(`In field '${key}': ${e.message}`);
36
+ }
37
+ }
38
+ return result;
39
+ })
40
+ };
41
+
42
+ // Configuração Schema para o nosso servidor
43
+ export const configSchema = z.object({
44
+ port: z.number(),
45
+ root: z.string(),
46
+ open: z.string(), // boolean as string 'true'/'false' simplificado para CLI
47
+ spa: z.string(), // boolean as string 'true'/'false' para suporte SPA
48
+ https: z.string() // boolean as string 'true'/'false' para modo HTTPS
49
+ });
50
+
51
+ export type Config = ReturnType<typeof configSchema.parse>;
package/src/watcher.ts ADDED
@@ -0,0 +1,63 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { EventEmitter } from 'node:events';
4
+
5
+ export class Watcher extends EventEmitter {
6
+ private root: string;
7
+ private timeout: NodeJS.Timeout | null = null;
8
+ private watcher: fs.FSWatcher | null = null;
9
+
10
+ constructor(root: string) {
11
+ super();
12
+ this.root = path.resolve(root);
13
+ }
14
+
15
+ start() {
16
+ if (!fs.existsSync(this.root)) {
17
+ console.error(`❌ Diretório não encontrado: ${this.root}`);
18
+ return;
19
+ }
20
+
21
+ try {
22
+ // Recursive watch é suportado na maioria dos OS modernos Node v20+
23
+ // No Linux pode ter limitações dependendo do FS, mas para dev local funciona bem.
24
+ this.watcher = fs.watch(this.root, { recursive: true }, (eventType, filename) => {
25
+ if (filename && !this.isIgnored(filename.toString())) {
26
+ this.debounceChange(filename.toString());
27
+ }
28
+ });
29
+ console.log(`👀 Observando mudanças em: ${this.root}`);
30
+ } catch (err) {
31
+ console.error("Erro ao iniciar watcher:", err);
32
+ // Fallback para não-recursivo se falhar (ex: Linux kernels antigos)
33
+ console.warn("⚠️ Fallback para watcher não recursivo.");
34
+ this.watcher = fs.watch(this.root, (event, filename) => {
35
+ if (filename) this.debounceChange(filename.toString());
36
+ });
37
+ }
38
+ }
39
+
40
+ private isIgnored(filename: string): boolean {
41
+ // Ignorar node_modules e arquivos ocultos (.git, etc)
42
+ return filename.includes('node_modules') ||
43
+ filename.includes('.git') ||
44
+ filename.endsWith('.tmp');
45
+ }
46
+
47
+ private debounceChange(filename: string) {
48
+ // Evita múltiplos disparos (ex: salvar arquivo dispara 2 eventos 'change' e 'rename')
49
+ if (this.timeout) clearTimeout(this.timeout);
50
+
51
+ this.timeout = setTimeout(() => {
52
+ console.log(`🔄 Arquivo alterado: ${filename}`);
53
+ this.emit('change', filename);
54
+ }, 100); // 100ms debounce
55
+ }
56
+
57
+ stop() {
58
+ if (this.watcher) {
59
+ this.watcher.close();
60
+ this.watcher = null;
61
+ }
62
+ }
63
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true
12
+ },
13
+ "include": ["src/**/*"],
14
+ "exclude": ["node_modules"]
15
+ }