javascript-solid-server 0.0.84 → 0.0.85
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/package.json +1 -1
- package/src/notifications/events.js +55 -0
- package/src/server.js +11 -0
package/package.json
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { EventEmitter } from 'events';
|
|
9
|
+
import { watch } from 'fs';
|
|
10
|
+
import { join, relative } from 'path';
|
|
9
11
|
|
|
10
12
|
// Singleton event emitter for resource changes
|
|
11
13
|
export const resourceEvents = new EventEmitter();
|
|
@@ -20,3 +22,56 @@ resourceEvents.setMaxListeners(1000);
|
|
|
20
22
|
export function emitChange(resourceUrl) {
|
|
21
23
|
resourceEvents.emit('change', resourceUrl);
|
|
22
24
|
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Start watching filesystem for changes and emit notifications
|
|
28
|
+
* @param {string} rootDir - Directory to watch
|
|
29
|
+
* @param {string} baseUrl - Base URL for constructing resource URLs (e.g., http://localhost:3000)
|
|
30
|
+
*/
|
|
31
|
+
export function startFileWatcher(rootDir, baseUrl) {
|
|
32
|
+
// Debounce map to avoid duplicate events (editors often save multiple times)
|
|
33
|
+
const debounceMap = new Map();
|
|
34
|
+
const DEBOUNCE_MS = 100;
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const watcher = watch(rootDir, { recursive: true }, (eventType, filename) => {
|
|
38
|
+
if (!filename) return;
|
|
39
|
+
|
|
40
|
+
// Skip hidden files and common temp files
|
|
41
|
+
if (filename.startsWith('.') || filename.endsWith('~') || filename.endsWith('.swp')) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Debounce: skip if we just emitted for this file
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
const lastEmit = debounceMap.get(filename);
|
|
48
|
+
if (lastEmit && now - lastEmit < DEBOUNCE_MS) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
debounceMap.set(filename, now);
|
|
52
|
+
|
|
53
|
+
// Clean up old debounce entries periodically
|
|
54
|
+
if (debounceMap.size > 1000) {
|
|
55
|
+
for (const [key, time] of debounceMap) {
|
|
56
|
+
if (now - time > 5000) debounceMap.delete(key);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Construct resource URL
|
|
61
|
+
const resourcePath = '/' + filename.replace(/\\/g, '/');
|
|
62
|
+
const resourceUrl = baseUrl.replace(/\/$/, '') + resourcePath;
|
|
63
|
+
|
|
64
|
+
emitChange(resourceUrl);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Handle watcher errors gracefully
|
|
68
|
+
watcher.on('error', (err) => {
|
|
69
|
+
console.error('File watcher error:', err.message);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return watcher;
|
|
73
|
+
} catch (err) {
|
|
74
|
+
console.error('Failed to start file watcher:', err.message);
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
package/src/server.js
CHANGED
|
@@ -9,6 +9,7 @@ import * as storage from './storage/filesystem.js';
|
|
|
9
9
|
import { getCorsHeaders } from './ldp/headers.js';
|
|
10
10
|
import { authorize, handleUnauthorized } from './auth/middleware.js';
|
|
11
11
|
import { notificationsPlugin } from './notifications/index.js';
|
|
12
|
+
import { startFileWatcher } from './notifications/events.js';
|
|
12
13
|
import { idpPlugin } from './idp/index.js';
|
|
13
14
|
import { isGitRequest, isGitWriteOperation, handleGit } from './handlers/git.js';
|
|
14
15
|
import { AccessMode } from './wac/parser.js';
|
|
@@ -542,6 +543,16 @@ export function createServer(options = {}) {
|
|
|
542
543
|
// Note: Quota not initialized for root-level pods (no user directory)
|
|
543
544
|
}
|
|
544
545
|
|
|
546
|
+
// Start file watcher for live reload (watches filesystem for external changes)
|
|
547
|
+
if (liveReloadEnabled) {
|
|
548
|
+
const dataRoot = options.root || process.env.DATA_ROOT || './data';
|
|
549
|
+
const protocol = options.ssl ? 'https' : 'http';
|
|
550
|
+
// Use configured port, or default; actual URL will be localhost
|
|
551
|
+
const port = options.port || 3000;
|
|
552
|
+
const baseUrl = `${protocol}://localhost:${port}`;
|
|
553
|
+
startFileWatcher(dataRoot, baseUrl);
|
|
554
|
+
}
|
|
555
|
+
|
|
545
556
|
return fastify;
|
|
546
557
|
}
|
|
547
558
|
|