@zap-js/client 0.0.2 → 0.0.4
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 +310 -24
- package/bin/zap +0 -0
- package/bin/zap-codegen +0 -0
- package/dist/cli/commands/build.d.ts +11 -0
- package/dist/cli/commands/build.js +282 -0
- package/dist/cli/commands/codegen.d.ts +8 -0
- package/dist/cli/commands/codegen.js +95 -0
- package/dist/cli/commands/dev.d.ts +20 -0
- package/dist/cli/commands/dev.js +78 -0
- package/dist/cli/commands/new.d.ts +9 -0
- package/dist/cli/commands/new.js +307 -0
- package/dist/cli/commands/routes-old.d.ts +9 -0
- package/dist/cli/commands/routes-old.js +106 -0
- package/dist/cli/commands/routes.d.ts +11 -0
- package/dist/cli/commands/routes.js +280 -0
- package/dist/cli/commands/serve.d.ts +17 -0
- package/dist/cli/commands/serve.js +386 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +76 -0
- package/dist/cli/utils/index.d.ts +2 -0
- package/dist/cli/utils/index.js +2 -0
- package/dist/cli/utils/logger.d.ts +84 -0
- package/dist/cli/utils/logger.js +181 -0
- package/dist/cli/utils/port-finder.d.ts +8 -0
- package/dist/cli/utils/port-finder.js +48 -0
- package/dist/dev-server/codegen-runner.d.ts +41 -0
- package/dist/dev-server/codegen-runner.js +172 -0
- package/dist/dev-server/hot-reload.d.ts +72 -0
- package/dist/dev-server/hot-reload.js +280 -0
- package/dist/dev-server/index.d.ts +8 -0
- package/dist/dev-server/index.js +8 -0
- package/dist/dev-server/route-scanner.d.ts +71 -0
- package/dist/dev-server/route-scanner.js +114 -0
- package/dist/dev-server/rust-builder.d.ts +66 -0
- package/dist/dev-server/rust-builder.js +286 -0
- package/dist/dev-server/server.d.ts +147 -0
- package/dist/dev-server/server.js +658 -0
- package/dist/dev-server/vite-proxy.d.ts +56 -0
- package/dist/dev-server/vite-proxy.js +212 -0
- package/dist/dev-server/watcher.d.ts +48 -0
- package/dist/dev-server/watcher.js +127 -0
- package/dist/router/codegen-enhanced.d.ts +5 -0
- package/dist/router/codegen-enhanced.js +275 -0
- package/dist/router/codegen.d.ts +17 -0
- package/dist/router/codegen.js +654 -0
- package/dist/router/index.d.ts +16 -0
- package/dist/router/index.js +19 -0
- package/dist/router/scanner.d.ts +86 -0
- package/dist/router/scanner.js +689 -0
- package/dist/router/ssg.d.ts +115 -0
- package/dist/router/ssg.js +202 -0
- package/dist/router/types.d.ts +124 -0
- package/dist/router/types.js +9 -0
- package/dist/router/watch.d.ts +38 -0
- package/dist/router/watch.js +135 -0
- package/dist/runtime/csrf.d.ts +146 -0
- package/dist/runtime/csrf.js +166 -0
- package/dist/runtime/error-boundary.d.ts +129 -0
- package/dist/runtime/error-boundary.js +287 -0
- package/dist/runtime/hooks.d.ts +83 -0
- package/dist/runtime/hooks.js +96 -0
- package/dist/runtime/index.d.ts +229 -0
- package/dist/runtime/index.js +449 -0
- package/dist/runtime/ipc-client.d.ts +144 -0
- package/dist/runtime/ipc-client.js +621 -0
- package/dist/runtime/logger.d.ts +71 -0
- package/dist/runtime/logger.js +164 -0
- package/dist/runtime/middleware.d.ts +66 -0
- package/dist/runtime/middleware.js +114 -0
- package/dist/runtime/process-manager.d.ts +51 -0
- package/dist/runtime/process-manager.js +207 -0
- package/dist/runtime/router-simple.d.ts +98 -0
- package/dist/runtime/router-simple.js +330 -0
- package/dist/runtime/router.d.ts +103 -0
- package/dist/runtime/router.js +435 -0
- package/dist/runtime/rpc-client.d.ts +35 -0
- package/dist/runtime/rpc-client.js +140 -0
- package/dist/runtime/streaming-utils.d.ts +86 -0
- package/dist/runtime/streaming-utils.js +150 -0
- package/dist/runtime/types.d.ts +465 -0
- package/dist/runtime/types.js +60 -0
- package/dist/runtime/websockets-utils.d.ts +50 -0
- package/dist/runtime/websockets-utils.js +92 -0
- package/package.json +30 -20
- package/index.js +0 -29
- package/internal/cli/package.json +0 -46
- package/internal/cli/tsconfig.tsbuildinfo +0 -1
- package/internal/dev-server/node_modules/ora/index.d.ts +0 -332
- package/internal/dev-server/node_modules/ora/index.js +0 -416
- package/internal/dev-server/node_modules/ora/license +0 -9
- package/internal/dev-server/node_modules/ora/node_modules/string-width/index.d.ts +0 -36
- package/internal/dev-server/node_modules/ora/node_modules/string-width/index.js +0 -65
- package/internal/dev-server/node_modules/ora/node_modules/string-width/license +0 -9
- package/internal/dev-server/node_modules/ora/node_modules/string-width/node_modules/emoji-regex/LICENSE-MIT.txt +0 -20
- package/internal/dev-server/node_modules/ora/node_modules/string-width/node_modules/emoji-regex/README.md +0 -107
- package/internal/dev-server/node_modules/ora/node_modules/string-width/node_modules/emoji-regex/index.d.ts +0 -3
- package/internal/dev-server/node_modules/ora/node_modules/string-width/node_modules/emoji-regex/index.js +0 -4
- package/internal/dev-server/node_modules/ora/node_modules/string-width/node_modules/emoji-regex/index.mjs +0 -4
- package/internal/dev-server/node_modules/ora/node_modules/string-width/node_modules/emoji-regex/package.json +0 -46
- package/internal/dev-server/node_modules/ora/node_modules/string-width/package.json +0 -60
- package/internal/dev-server/node_modules/ora/node_modules/string-width/readme.md +0 -62
- package/internal/dev-server/node_modules/ora/package.json +0 -66
- package/internal/dev-server/node_modules/ora/readme.md +0 -325
- package/internal/dev-server/package.json +0 -41
- package/internal/router/package.json +0 -28
- package/internal/runtime/package.json +0 -41
- package/internal/runtime/src/error-boundary.tsx +0 -476
- package/internal/runtime/src/router-simple.tsx +0 -640
- package/internal/runtime/src/router.tsx +0 -771
- package/internal/runtime/tsconfig.tsbuildinfo +0 -1
- package/src/errors.js +0 -33
- package/src/logger.js +0 -10
- package/src/middleware.js +0 -32
- package/src/router.js +0 -41
- package/src/types.js +0 -39
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
export interface ViteProxyConfig {
|
|
3
|
+
projectDir: string;
|
|
4
|
+
port?: number;
|
|
5
|
+
host?: string;
|
|
6
|
+
configFile?: string;
|
|
7
|
+
}
|
|
8
|
+
export type ViteStatus = 'stopped' | 'starting' | 'running' | 'error';
|
|
9
|
+
/**
|
|
10
|
+
* ViteProxy - Manages Vite dev server for frontend development
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - Automatic Vite dev server lifecycle management
|
|
14
|
+
* - Port detection and configuration
|
|
15
|
+
* - HMR support passthrough
|
|
16
|
+
* - Error handling and restart
|
|
17
|
+
*/
|
|
18
|
+
export declare class ViteProxy extends EventEmitter {
|
|
19
|
+
private config;
|
|
20
|
+
private process;
|
|
21
|
+
private status;
|
|
22
|
+
private actualPort;
|
|
23
|
+
constructor(config: ViteProxyConfig);
|
|
24
|
+
/**
|
|
25
|
+
* Get current status
|
|
26
|
+
*/
|
|
27
|
+
getStatus(): ViteStatus;
|
|
28
|
+
/**
|
|
29
|
+
* Get the port Vite is running on
|
|
30
|
+
*/
|
|
31
|
+
getPort(): number | null;
|
|
32
|
+
/**
|
|
33
|
+
* Start Vite dev server
|
|
34
|
+
*/
|
|
35
|
+
start(): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Stop Vite dev server
|
|
38
|
+
*/
|
|
39
|
+
stop(): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Restart Vite dev server
|
|
42
|
+
*/
|
|
43
|
+
restart(): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Check if Vite is healthy
|
|
46
|
+
*/
|
|
47
|
+
healthCheck(): Promise<boolean>;
|
|
48
|
+
/**
|
|
49
|
+
* Detect the best package runner available
|
|
50
|
+
*/
|
|
51
|
+
private detectPackageRunner;
|
|
52
|
+
/**
|
|
53
|
+
* Get the base URL for the Vite server
|
|
54
|
+
*/
|
|
55
|
+
getBaseUrl(): string | null;
|
|
56
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { spawn, execSync } from 'child_process';
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
import http from 'http';
|
|
4
|
+
/**
|
|
5
|
+
* ViteProxy - Manages Vite dev server for frontend development
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Automatic Vite dev server lifecycle management
|
|
9
|
+
* - Port detection and configuration
|
|
10
|
+
* - HMR support passthrough
|
|
11
|
+
* - Error handling and restart
|
|
12
|
+
*/
|
|
13
|
+
export class ViteProxy extends EventEmitter {
|
|
14
|
+
constructor(config) {
|
|
15
|
+
super();
|
|
16
|
+
this.process = null;
|
|
17
|
+
this.status = 'stopped';
|
|
18
|
+
this.actualPort = null;
|
|
19
|
+
this.config = {
|
|
20
|
+
port: 5173,
|
|
21
|
+
host: '127.0.0.1',
|
|
22
|
+
...config,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Get current status
|
|
27
|
+
*/
|
|
28
|
+
getStatus() {
|
|
29
|
+
return this.status;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get the port Vite is running on
|
|
33
|
+
*/
|
|
34
|
+
getPort() {
|
|
35
|
+
return this.actualPort;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Start Vite dev server
|
|
39
|
+
*/
|
|
40
|
+
async start() {
|
|
41
|
+
if (this.status === 'running') {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
this.status = 'starting';
|
|
45
|
+
this.emit('starting');
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
const args = [
|
|
48
|
+
'vite',
|
|
49
|
+
'--port', String(this.config.port),
|
|
50
|
+
'--host', this.config.host,
|
|
51
|
+
'--strictPort',
|
|
52
|
+
];
|
|
53
|
+
if (this.config.configFile) {
|
|
54
|
+
args.push('--config', this.config.configFile);
|
|
55
|
+
}
|
|
56
|
+
// Try to use bunx first, fall back to npx
|
|
57
|
+
const runner = this.detectPackageRunner();
|
|
58
|
+
console.log(`[vite-proxy] Starting with: ${runner} ${args.join(' ')}`);
|
|
59
|
+
console.log(`[vite-proxy] Working directory: ${this.config.projectDir}`);
|
|
60
|
+
this.process = spawn(runner, args, {
|
|
61
|
+
cwd: this.config.projectDir,
|
|
62
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
63
|
+
env: {
|
|
64
|
+
...process.env,
|
|
65
|
+
FORCE_COLOR: '1',
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
let startupComplete = false;
|
|
69
|
+
this.process.stdout?.on('data', (data) => {
|
|
70
|
+
const output = data.toString();
|
|
71
|
+
console.log(`[vite-proxy stdout] ${output.trim()}`);
|
|
72
|
+
this.emit('output', output);
|
|
73
|
+
// Detect when Vite is ready - check multiple patterns
|
|
74
|
+
const isReady = output.includes('Local:') ||
|
|
75
|
+
output.includes('ready in') ||
|
|
76
|
+
output.includes('VITE') && output.includes('localhost');
|
|
77
|
+
if (!startupComplete && isReady) {
|
|
78
|
+
startupComplete = true;
|
|
79
|
+
this.status = 'running';
|
|
80
|
+
// Parse actual port from output - try multiple patterns
|
|
81
|
+
const portMatch = output.match(/localhost:(\d+)/) ||
|
|
82
|
+
output.match(/127\.0\.0\.1:(\d+)/) ||
|
|
83
|
+
output.match(/:(\d+)\//);
|
|
84
|
+
if (portMatch) {
|
|
85
|
+
this.actualPort = parseInt(portMatch[1], 10);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
this.actualPort = this.config.port;
|
|
89
|
+
}
|
|
90
|
+
console.log(`[vite-proxy] Ready on port ${this.actualPort}`);
|
|
91
|
+
this.emit('ready', this.actualPort);
|
|
92
|
+
resolve();
|
|
93
|
+
}
|
|
94
|
+
// Detect HMR updates
|
|
95
|
+
if (output.includes('[vite] hmr update')) {
|
|
96
|
+
this.emit('hmr-update');
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
this.process.stderr?.on('data', (data) => {
|
|
100
|
+
const output = data.toString();
|
|
101
|
+
console.log(`[vite-proxy stderr] ${output.trim()}`);
|
|
102
|
+
this.emit('stderr', output);
|
|
103
|
+
// Check for critical errors (but not just any lowercase 'error')
|
|
104
|
+
if (output.includes('Error:') || output.includes('EADDRINUSE')) {
|
|
105
|
+
this.emit('error', new Error(output));
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
this.process.on('close', (code) => {
|
|
109
|
+
console.log(`[vite-proxy] Process closed with code ${code}`);
|
|
110
|
+
const wasRunning = this.status === 'running';
|
|
111
|
+
this.status = 'stopped';
|
|
112
|
+
this.actualPort = null;
|
|
113
|
+
this.process = null;
|
|
114
|
+
if (wasRunning && code !== 0) {
|
|
115
|
+
this.emit('crash', code);
|
|
116
|
+
}
|
|
117
|
+
this.emit('exit', code);
|
|
118
|
+
if (!startupComplete) {
|
|
119
|
+
reject(new Error(`Vite exited with code ${code} before starting`));
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
this.process.on('error', (err) => {
|
|
123
|
+
console.log(`[vite-proxy] Process error: ${err.message}`);
|
|
124
|
+
this.status = 'error';
|
|
125
|
+
this.emit('error', err);
|
|
126
|
+
reject(err);
|
|
127
|
+
});
|
|
128
|
+
// Timeout for startup
|
|
129
|
+
setTimeout(() => {
|
|
130
|
+
if (!startupComplete) {
|
|
131
|
+
console.log(`[vite-proxy] Startup timeout - still waiting...`);
|
|
132
|
+
this.emit('timeout');
|
|
133
|
+
// Don't reject - Vite might still be starting
|
|
134
|
+
}
|
|
135
|
+
}, 30000);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Stop Vite dev server
|
|
140
|
+
*/
|
|
141
|
+
async stop() {
|
|
142
|
+
if (!this.process) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
return new Promise((resolve) => {
|
|
146
|
+
if (!this.process) {
|
|
147
|
+
resolve();
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const timeout = setTimeout(() => {
|
|
151
|
+
if (this.process && !this.process.killed) {
|
|
152
|
+
this.process.kill('SIGKILL');
|
|
153
|
+
}
|
|
154
|
+
}, 5000);
|
|
155
|
+
this.process.once('exit', () => {
|
|
156
|
+
clearTimeout(timeout);
|
|
157
|
+
this.process = null;
|
|
158
|
+
this.status = 'stopped';
|
|
159
|
+
this.actualPort = null;
|
|
160
|
+
resolve();
|
|
161
|
+
});
|
|
162
|
+
this.process.kill('SIGTERM');
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Restart Vite dev server
|
|
167
|
+
*/
|
|
168
|
+
async restart() {
|
|
169
|
+
await this.stop();
|
|
170
|
+
await this.start();
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Check if Vite is healthy
|
|
174
|
+
*/
|
|
175
|
+
async healthCheck() {
|
|
176
|
+
if (!this.actualPort || this.status !== 'running') {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
return new Promise((resolve) => {
|
|
180
|
+
const req = http.get(`http://${this.config.host}:${this.actualPort}/`, { timeout: 2000 }, (res) => {
|
|
181
|
+
resolve(res.statusCode === 200);
|
|
182
|
+
});
|
|
183
|
+
req.on('error', () => resolve(false));
|
|
184
|
+
req.on('timeout', () => {
|
|
185
|
+
req.destroy();
|
|
186
|
+
resolve(false);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Detect the best package runner available
|
|
192
|
+
*/
|
|
193
|
+
detectPackageRunner() {
|
|
194
|
+
// Check if bun is available
|
|
195
|
+
try {
|
|
196
|
+
execSync('bun --version', { stdio: 'ignore' });
|
|
197
|
+
return 'bunx';
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
return 'npx';
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Get the base URL for the Vite server
|
|
205
|
+
*/
|
|
206
|
+
getBaseUrl() {
|
|
207
|
+
if (!this.actualPort) {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
return `http://${this.config.host}:${this.actualPort}`;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
export type WatchEventType = 'add' | 'change' | 'unlink';
|
|
3
|
+
export interface WatchEvent {
|
|
4
|
+
type: WatchEventType;
|
|
5
|
+
path: string;
|
|
6
|
+
category: 'rust' | 'typescript' | 'config' | 'unknown';
|
|
7
|
+
}
|
|
8
|
+
export interface WatcherConfig {
|
|
9
|
+
rootDir: string;
|
|
10
|
+
rustDirs?: string[];
|
|
11
|
+
tsDirs?: string[];
|
|
12
|
+
ignored?: string[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* FileWatcher - Monitors file changes and categorizes them
|
|
16
|
+
*
|
|
17
|
+
* Watches for:
|
|
18
|
+
* - Rust source changes (.rs, Cargo.toml)
|
|
19
|
+
* - TypeScript/JS changes (.ts, .tsx, .js, .jsx)
|
|
20
|
+
* - Config changes (package.json, tsconfig.json, vite.config.*)
|
|
21
|
+
*/
|
|
22
|
+
export declare class FileWatcher extends EventEmitter {
|
|
23
|
+
private watcher;
|
|
24
|
+
private config;
|
|
25
|
+
private debounceTimers;
|
|
26
|
+
private debounceMs;
|
|
27
|
+
constructor(config: WatcherConfig);
|
|
28
|
+
/**
|
|
29
|
+
* Start watching for file changes
|
|
30
|
+
*/
|
|
31
|
+
start(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Stop watching
|
|
34
|
+
*/
|
|
35
|
+
stop(): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Handle a file event with debouncing
|
|
38
|
+
*/
|
|
39
|
+
private handleEvent;
|
|
40
|
+
/**
|
|
41
|
+
* Categorize a file based on its extension
|
|
42
|
+
*/
|
|
43
|
+
private categorizeFile;
|
|
44
|
+
/**
|
|
45
|
+
* Set debounce timing
|
|
46
|
+
*/
|
|
47
|
+
setDebounce(ms: number): void;
|
|
48
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import chokidar from 'chokidar';
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
/**
|
|
5
|
+
* FileWatcher - Monitors file changes and categorizes them
|
|
6
|
+
*
|
|
7
|
+
* Watches for:
|
|
8
|
+
* - Rust source changes (.rs, Cargo.toml)
|
|
9
|
+
* - TypeScript/JS changes (.ts, .tsx, .js, .jsx)
|
|
10
|
+
* - Config changes (package.json, tsconfig.json, vite.config.*)
|
|
11
|
+
*/
|
|
12
|
+
export class FileWatcher extends EventEmitter {
|
|
13
|
+
constructor(config) {
|
|
14
|
+
super();
|
|
15
|
+
this.watcher = null;
|
|
16
|
+
this.debounceTimers = new Map();
|
|
17
|
+
this.debounceMs = 100;
|
|
18
|
+
this.config = {
|
|
19
|
+
rustDirs: ['src', 'packages'],
|
|
20
|
+
tsDirs: ['src', 'packages'],
|
|
21
|
+
ignored: [
|
|
22
|
+
'**/node_modules/**',
|
|
23
|
+
'**/target/**',
|
|
24
|
+
'**/dist/**',
|
|
25
|
+
'**/.git/**',
|
|
26
|
+
'**/build/**',
|
|
27
|
+
'**/*.d.ts',
|
|
28
|
+
],
|
|
29
|
+
...config,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Start watching for file changes
|
|
34
|
+
*/
|
|
35
|
+
start() {
|
|
36
|
+
const watchPaths = [
|
|
37
|
+
// Rust files
|
|
38
|
+
path.join(this.config.rootDir, '**/*.rs'),
|
|
39
|
+
path.join(this.config.rootDir, '**/Cargo.toml'),
|
|
40
|
+
// TypeScript files
|
|
41
|
+
path.join(this.config.rootDir, '**/*.ts'),
|
|
42
|
+
path.join(this.config.rootDir, '**/*.tsx'),
|
|
43
|
+
path.join(this.config.rootDir, '**/*.js'),
|
|
44
|
+
path.join(this.config.rootDir, '**/*.jsx'),
|
|
45
|
+
// Config files
|
|
46
|
+
path.join(this.config.rootDir, '**/package.json'),
|
|
47
|
+
path.join(this.config.rootDir, '**/tsconfig.json'),
|
|
48
|
+
path.join(this.config.rootDir, '**/vite.config.*'),
|
|
49
|
+
];
|
|
50
|
+
this.watcher = chokidar.watch(watchPaths, {
|
|
51
|
+
ignored: this.config.ignored,
|
|
52
|
+
persistent: true,
|
|
53
|
+
ignoreInitial: true,
|
|
54
|
+
awaitWriteFinish: {
|
|
55
|
+
stabilityThreshold: 50,
|
|
56
|
+
pollInterval: 10,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
this.watcher.on('add', (filePath) => this.handleEvent('add', filePath));
|
|
60
|
+
this.watcher.on('change', (filePath) => this.handleEvent('change', filePath));
|
|
61
|
+
this.watcher.on('unlink', (filePath) => this.handleEvent('unlink', filePath));
|
|
62
|
+
this.watcher.on('error', (error) => this.emit('error', error));
|
|
63
|
+
this.watcher.on('ready', () => this.emit('ready'));
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Stop watching
|
|
67
|
+
*/
|
|
68
|
+
async stop() {
|
|
69
|
+
if (this.watcher) {
|
|
70
|
+
await this.watcher.close();
|
|
71
|
+
this.watcher = null;
|
|
72
|
+
}
|
|
73
|
+
// Clear all debounce timers
|
|
74
|
+
for (const timer of this.debounceTimers.values()) {
|
|
75
|
+
clearTimeout(timer);
|
|
76
|
+
}
|
|
77
|
+
this.debounceTimers.clear();
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Handle a file event with debouncing
|
|
81
|
+
*/
|
|
82
|
+
handleEvent(type, filePath) {
|
|
83
|
+
// Debounce rapid changes to the same file
|
|
84
|
+
const existingTimer = this.debounceTimers.get(filePath);
|
|
85
|
+
if (existingTimer) {
|
|
86
|
+
clearTimeout(existingTimer);
|
|
87
|
+
}
|
|
88
|
+
const timer = setTimeout(() => {
|
|
89
|
+
this.debounceTimers.delete(filePath);
|
|
90
|
+
const event = {
|
|
91
|
+
type,
|
|
92
|
+
path: filePath,
|
|
93
|
+
category: this.categorizeFile(filePath),
|
|
94
|
+
};
|
|
95
|
+
this.emit('change', event);
|
|
96
|
+
this.emit(event.category, event);
|
|
97
|
+
}, this.debounceMs);
|
|
98
|
+
this.debounceTimers.set(filePath, timer);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Categorize a file based on its extension
|
|
102
|
+
*/
|
|
103
|
+
categorizeFile(filePath) {
|
|
104
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
105
|
+
const basename = path.basename(filePath);
|
|
106
|
+
// Rust files
|
|
107
|
+
if (ext === '.rs' || basename === 'Cargo.toml') {
|
|
108
|
+
return 'rust';
|
|
109
|
+
}
|
|
110
|
+
// TypeScript/JavaScript files
|
|
111
|
+
if (['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'].includes(ext)) {
|
|
112
|
+
return 'typescript';
|
|
113
|
+
}
|
|
114
|
+
// Config files
|
|
115
|
+
if (['package.json', 'tsconfig.json'].includes(basename) ||
|
|
116
|
+
basename.startsWith('vite.config.')) {
|
|
117
|
+
return 'config';
|
|
118
|
+
}
|
|
119
|
+
return 'unknown';
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Set debounce timing
|
|
123
|
+
*/
|
|
124
|
+
setDebounce(ms) {
|
|
125
|
+
this.debounceMs = ms;
|
|
126
|
+
}
|
|
127
|
+
}
|