@e-mc/watch 0.11.7 → 0.12.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.
- package/README.md +9 -8
- package/filegroup/index.js +61 -46
- package/index.js +143 -93
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @e-mc/watch
|
|
2
2
|
|
|
3
|
-
* NodeJS
|
|
4
|
-
*
|
|
3
|
+
* NodeJS 18
|
|
4
|
+
* ES2022
|
|
5
5
|
|
|
6
6
|
## General Usage
|
|
7
7
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
## Interface
|
|
11
11
|
|
|
12
|
-
* [View Source](https://www.unpkg.com/@e-mc/types@0.
|
|
12
|
+
* [View Source](https://www.unpkg.com/@e-mc/types@0.12.0/lib/index.d.ts)
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
import type { IFileManager, ModuleConstructor } from "./index";
|
|
@@ -31,6 +31,7 @@ interface IWatch extends IClient<IFileManager, WatchModule, ModifiedPostFinalize
|
|
|
31
31
|
setSSLKey(value: string): boolean;
|
|
32
32
|
setSSLCert(value: string): boolean;
|
|
33
33
|
hasSecureProtocol(): boolean;
|
|
34
|
+
getRecursiveFiles(watch: IFileGroup<ExternalAsset>): [string, string[]][];
|
|
34
35
|
whenModified?(assets: ExternalAsset[], postFinalize: PostFinalizeCallback): IFileManager;
|
|
35
36
|
whenModified?(assets: ExternalAsset[], sanitize?: boolean, postFinalize?: PostFinalizeCallback): IFileManager;
|
|
36
37
|
set assets(value: ExternalAsset[]);
|
|
@@ -109,11 +110,11 @@ instance.start(assets, { disk_read: ["/path/workspace/output/**"] });
|
|
|
109
110
|
|
|
110
111
|
## References
|
|
111
112
|
|
|
112
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
113
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
114
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
115
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
116
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
113
|
+
- https://www.unpkg.com/@e-mc/types@0.12.0/lib/asset.d.ts
|
|
114
|
+
- https://www.unpkg.com/@e-mc/types@0.12.0/lib/core.d.ts
|
|
115
|
+
- https://www.unpkg.com/@e-mc/types@0.12.0/lib/filemanager.d.ts
|
|
116
|
+
- https://www.unpkg.com/@e-mc/types@0.12.0/lib/settings.d.ts
|
|
117
|
+
- https://www.unpkg.com/@e-mc/types@0.12.0/lib/watch.d.ts
|
|
117
118
|
|
|
118
119
|
* https://www.npmjs.com/package/@types/ws
|
|
119
120
|
|
package/filegroup/index.js
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var _a, _b, _c, _d, _e, _f;
|
|
3
2
|
const util = require("node:util");
|
|
3
|
+
const pm = require("picomatch");
|
|
4
4
|
const ws = require("ws");
|
|
5
5
|
const types_1 = require("@e-mc/types");
|
|
6
6
|
const core_1 = require("@e-mc/core");
|
|
7
|
-
const kServer = Symbol('server');
|
|
8
|
-
const kStarted = Symbol('started');
|
|
9
|
-
const kPaused = Symbol('paused');
|
|
10
|
-
const kAssets = Symbol('assets');
|
|
11
|
-
const kSockets = Symbol('sockets');
|
|
12
|
-
const kStartTime = Symbol('startTime');
|
|
13
|
-
const kUri = Symbol('uri');
|
|
14
|
-
const kEtag = Symbol('etag');
|
|
15
|
-
const kLastModified = Symbol('lastModified');
|
|
16
7
|
class SocketRequest {
|
|
8
|
+
expires;
|
|
9
|
+
socketId;
|
|
10
|
+
id;
|
|
17
11
|
constructor(expires, socketId, id = '') {
|
|
18
12
|
this.expires = expires;
|
|
19
13
|
this.socketId = socketId;
|
|
@@ -25,6 +19,8 @@ class SocketRequest {
|
|
|
25
19
|
}
|
|
26
20
|
}
|
|
27
21
|
class FileGroup extends core_1.AbortComponent {
|
|
22
|
+
static CONNECTION_TIMEOUT = 10 * 60000;
|
|
23
|
+
static CLIENT_SESSION = new Map();
|
|
28
24
|
static checkTimeout(client) {
|
|
29
25
|
if (client.readyState !== ws.OPEN) {
|
|
30
26
|
return false;
|
|
@@ -44,34 +40,45 @@ class FileGroup extends core_1.AbortComponent {
|
|
|
44
40
|
const watch = file.watch;
|
|
45
41
|
return (0, types_1.cloneObject)(file, (0, types_1.isPlainObject)(watch) && (0, types_1.isArray)(watch.assets) ? new WeakSet([watch.assets]) : true);
|
|
46
42
|
}
|
|
47
|
-
|
|
43
|
+
captured = false;
|
|
44
|
+
port = NaN;
|
|
45
|
+
secure = false;
|
|
46
|
+
hot = false;
|
|
47
|
+
always = false;
|
|
48
|
+
url;
|
|
49
|
+
document;
|
|
50
|
+
main;
|
|
51
|
+
bundleMain;
|
|
52
|
+
sourceFiles;
|
|
53
|
+
_related = [];
|
|
54
|
+
_abortable;
|
|
55
|
+
#server = null;
|
|
56
|
+
#started = false;
|
|
57
|
+
#paused = false;
|
|
58
|
+
#etag = '';
|
|
59
|
+
#lastModified = '';
|
|
60
|
+
#startTime;
|
|
61
|
+
#sockets = [];
|
|
62
|
+
#uri;
|
|
63
|
+
#assets;
|
|
64
|
+
#recursive;
|
|
65
|
+
constructor(uri, assets, startTime, abortable, recursive) {
|
|
48
66
|
super();
|
|
49
|
-
this
|
|
50
|
-
this
|
|
51
|
-
this.secure = false;
|
|
52
|
-
this.hot = false;
|
|
53
|
-
this.always = false;
|
|
54
|
-
this._related = [];
|
|
55
|
-
this._abortable = false;
|
|
56
|
-
this[_a] = null;
|
|
57
|
-
this[_b] = false;
|
|
58
|
-
this[_c] = false;
|
|
59
|
-
this[_d] = '';
|
|
60
|
-
this[_e] = '';
|
|
61
|
-
this[_f] = [];
|
|
62
|
-
this[kUri] = uri;
|
|
63
|
-
this[kAssets] = assets;
|
|
67
|
+
this.#uri = uri;
|
|
68
|
+
this.#assets = assets;
|
|
64
69
|
if (typeof startTime === 'boolean') {
|
|
70
|
+
recursive = abortable;
|
|
65
71
|
abortable = startTime;
|
|
66
72
|
startTime = undefined;
|
|
67
73
|
}
|
|
68
|
-
|
|
69
|
-
|
|
74
|
+
this._abortable = abortable === true;
|
|
75
|
+
this.#startTime = startTime || Date.now();
|
|
76
|
+
if (recursive && (0, types_1.supported)(19, 1)) {
|
|
77
|
+
this.#recursive = (Array.isArray(recursive) ? recursive : typeof recursive === 'string' ? [recursive] : []).map(value => core_1.Permission.toPosix(value));
|
|
70
78
|
}
|
|
71
|
-
this[kStartTime] = startTime || Date.now();
|
|
72
79
|
}
|
|
73
80
|
connection(server, port = 0, secure = false) {
|
|
74
|
-
this
|
|
81
|
+
this.#server = server;
|
|
75
82
|
if (port > 0) {
|
|
76
83
|
this.port = port;
|
|
77
84
|
}
|
|
@@ -120,32 +127,38 @@ class FileGroup extends core_1.AbortComponent {
|
|
|
120
127
|
return result;
|
|
121
128
|
}
|
|
122
129
|
pause() {
|
|
123
|
-
this
|
|
130
|
+
this.#paused = true;
|
|
124
131
|
}
|
|
125
132
|
resume() {
|
|
126
|
-
this
|
|
133
|
+
this.#paused = false;
|
|
127
134
|
}
|
|
128
135
|
reset() {
|
|
129
136
|
super.reset();
|
|
130
137
|
this.captured = false;
|
|
131
138
|
}
|
|
139
|
+
matchRecursive(value) {
|
|
140
|
+
if (!this.recursive) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
return this.#recursive?.length ? pm.isMatch(core_1.Permission.toPosix(value), this.#recursive, { nocase: process.platform === 'win32' }) : true;
|
|
144
|
+
}
|
|
132
145
|
get server() {
|
|
133
|
-
return this
|
|
146
|
+
return this.#server;
|
|
134
147
|
}
|
|
135
148
|
get uri() {
|
|
136
|
-
return this
|
|
149
|
+
return this.#uri;
|
|
137
150
|
}
|
|
138
151
|
get sockets() {
|
|
139
|
-
return this
|
|
152
|
+
return this.#sockets;
|
|
140
153
|
}
|
|
141
154
|
get startTime() {
|
|
142
|
-
return this
|
|
155
|
+
return this.#startTime;
|
|
143
156
|
}
|
|
144
157
|
get started() {
|
|
145
|
-
return this
|
|
158
|
+
return this.#started ||= Date.now() >= this.startTime;
|
|
146
159
|
}
|
|
147
160
|
get assets() {
|
|
148
|
-
return this
|
|
161
|
+
return this.#assets;
|
|
149
162
|
}
|
|
150
163
|
set related(value) {
|
|
151
164
|
this._related = value.map(item => {
|
|
@@ -170,19 +183,19 @@ class FileGroup extends core_1.AbortComponent {
|
|
|
170
183
|
}
|
|
171
184
|
set etag(value) {
|
|
172
185
|
if (typeof value === 'string') {
|
|
173
|
-
this
|
|
186
|
+
this.#etag = value;
|
|
174
187
|
}
|
|
175
188
|
}
|
|
176
189
|
get etag() {
|
|
177
|
-
return this
|
|
190
|
+
return this.#etag;
|
|
178
191
|
}
|
|
179
192
|
set lastModified(value) {
|
|
180
193
|
if (typeof value === 'string') {
|
|
181
|
-
this
|
|
194
|
+
this.#lastModified = value;
|
|
182
195
|
}
|
|
183
196
|
}
|
|
184
197
|
get lastModified() {
|
|
185
|
-
return this
|
|
198
|
+
return this.#etag ? '' : this.#lastModified;
|
|
186
199
|
}
|
|
187
200
|
get expires() {
|
|
188
201
|
let result = 0;
|
|
@@ -198,13 +211,15 @@ class FileGroup extends core_1.AbortComponent {
|
|
|
198
211
|
return this.sockets.every(item => item.expired);
|
|
199
212
|
}
|
|
200
213
|
get paused() {
|
|
201
|
-
return this
|
|
214
|
+
return this.#paused;
|
|
202
215
|
}
|
|
203
216
|
get abortable() {
|
|
204
217
|
return this._abortable;
|
|
205
218
|
}
|
|
219
|
+
get recursive() {
|
|
220
|
+
if (this.#recursive) {
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
206
224
|
}
|
|
207
|
-
_a = kServer, _b = kStarted, _c = kPaused, _d = kEtag, _e = kLastModified, _f = kSockets;
|
|
208
|
-
FileGroup.CONNECTION_TIMEOUT = 10 * 60000;
|
|
209
|
-
FileGroup.CLIENT_SESSION = new Map();
|
|
210
225
|
module.exports = FileGroup;
|
package/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
3
2
|
const path = require("node:path");
|
|
4
3
|
const fs = require("node:fs");
|
|
5
4
|
const https = require("node:https");
|
|
@@ -10,16 +9,7 @@ const core_1 = require("@e-mc/core");
|
|
|
10
9
|
const util_1 = require("@e-mc/request/util");
|
|
11
10
|
const request_1 = require("@e-mc/request");
|
|
12
11
|
const filegroup_1 = require("@e-mc/watch/filegroup");
|
|
13
|
-
const
|
|
14
|
-
const kPort = Symbol('port');
|
|
15
|
-
const kSecurePort = Symbol('securePort');
|
|
16
|
-
const kCa = Symbol('ca');
|
|
17
|
-
const kTlsKey = Symbol('tlsKey');
|
|
18
|
-
const kTlsCert = Symbol('tlsCert');
|
|
19
|
-
const kTlsVersion = Symbol('tlsVersion');
|
|
20
|
-
const kTlsPassphrase = Symbol('tlsPassphrase');
|
|
21
|
-
const kTlsConfig = Symbol('tlsConfig');
|
|
22
|
-
const kCiphers = Symbol('ciphers');
|
|
12
|
+
const kWatch = Symbol.for('watch:constructor');
|
|
23
13
|
const HTTP_MAP = new Map();
|
|
24
14
|
const DISK_MAP = new Map();
|
|
25
15
|
const PORT_MAP = new Map();
|
|
@@ -69,12 +59,6 @@ function wasAborted(result, current) {
|
|
|
69
59
|
current.abort();
|
|
70
60
|
}
|
|
71
61
|
}
|
|
72
|
-
function fatalError(instance, map, target, err) {
|
|
73
|
-
const uri = target.value.uri;
|
|
74
|
-
map.delete(uri);
|
|
75
|
-
abortTimeout(target);
|
|
76
|
-
instance.writeFail(["Unable to watch file", uri], err, 16);
|
|
77
|
-
}
|
|
78
62
|
function getErrorMessage(item, status) {
|
|
79
63
|
switch (status) {
|
|
80
64
|
case 1:
|
|
@@ -93,24 +77,8 @@ function getErrorMessage(item, status) {
|
|
|
93
77
|
const isMap = (value) => value ? value.size > 0 : false;
|
|
94
78
|
const formatDate = (value) => new Date(value).toLocaleString().replace(/\/20\d+, /, '@').replace(/:\d+ (AM|PM)$/, (...match) => match[1]);
|
|
95
79
|
class Watch extends core_1.Client {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
this.connectTimeout = Watch.PROCESS_TIMEOUT;
|
|
99
|
-
this._moduleName = 'watch';
|
|
100
|
-
this._assets = [];
|
|
101
|
-
this._extensions = [];
|
|
102
|
-
this._hostEvents = [];
|
|
103
|
-
this[_a] = types_1.THRESHOLD.WATCH_INTERVAL;
|
|
104
|
-
this[_b] = 80;
|
|
105
|
-
this[_c] = 443;
|
|
106
|
-
this[_d] = '';
|
|
107
|
-
this[_e] = '';
|
|
108
|
-
this[_f] = '';
|
|
109
|
-
this[_g] = '';
|
|
110
|
-
this[_h] = '';
|
|
111
|
-
this[_j] = undefined;
|
|
112
|
-
this[_k] = undefined;
|
|
113
|
-
}
|
|
80
|
+
static [kWatch] = true;
|
|
81
|
+
static PROCESS_TIMEOUT = 5 * 1000;
|
|
114
82
|
static createServer(port, secure, active) {
|
|
115
83
|
if (typeof secure === 'boolean') {
|
|
116
84
|
active = secure;
|
|
@@ -206,6 +174,24 @@ class Watch extends core_1.Client {
|
|
|
206
174
|
static isConnectionError(err) {
|
|
207
175
|
return (0, util_1.checkRetryable)(err);
|
|
208
176
|
}
|
|
177
|
+
connectTimeout = Watch.PROCESS_TIMEOUT;
|
|
178
|
+
_moduleName = 'watch';
|
|
179
|
+
_assets = [];
|
|
180
|
+
_extensions = [];
|
|
181
|
+
_recursiveMap = Object.create(null);
|
|
182
|
+
_hostEvents = [];
|
|
183
|
+
#internal = types_1.THRESHOLD.WATCH_INTERVAL;
|
|
184
|
+
#port = 80;
|
|
185
|
+
#securePort = 443;
|
|
186
|
+
#ca = '';
|
|
187
|
+
#ciphers = '';
|
|
188
|
+
#tlsKey = '';
|
|
189
|
+
#tlsCert = '';
|
|
190
|
+
#tlsPassphrase = '';
|
|
191
|
+
#tlsVersion = undefined;
|
|
192
|
+
#tlsConfig = undefined;
|
|
193
|
+
#recursiveTime = new WeakMap();
|
|
194
|
+
whenModified;
|
|
209
195
|
init(config) {
|
|
210
196
|
const { interval, port, secure } = this.module;
|
|
211
197
|
if (secure) {
|
|
@@ -280,7 +266,7 @@ class Watch extends core_1.Client {
|
|
|
280
266
|
if (!watch) {
|
|
281
267
|
continue;
|
|
282
268
|
}
|
|
283
|
-
let expires = 0, status = 0, wss = null, main, id, socketId, port, secure, hot, always, watched, message;
|
|
269
|
+
let expires = 0, status = 0, wss = null, main, id, socketId, port, secure, hot, always, recursive, watched, message;
|
|
284
270
|
if (watch === true && settings) {
|
|
285
271
|
const { uri, localUri, mimeType } = item;
|
|
286
272
|
watch = false;
|
|
@@ -292,8 +278,10 @@ class Watch extends core_1.Client {
|
|
|
292
278
|
}
|
|
293
279
|
}
|
|
294
280
|
if (!watch && localUri && !(watch = settings[localUri])) {
|
|
281
|
+
const pathname = core_1.Client.PLATFORM_WIN32 ? core_1.Client.toPosix(localUri) : localUri;
|
|
282
|
+
const options = core_1.Client.PLATFORM_WIN32 ? { nocase: true, matchBase: true, windows: true, posixSlashes: true } : { matchBase: true };
|
|
295
283
|
for (const pattern in settings) {
|
|
296
|
-
if ((0, types_1.hasGlob)(pattern) && pm.isMatch(
|
|
284
|
+
if ((0, types_1.hasGlob)(pattern) && pm.isMatch(pathname, pattern, options) && (watch = settings[pattern])) {
|
|
297
285
|
break;
|
|
298
286
|
}
|
|
299
287
|
}
|
|
@@ -308,27 +296,30 @@ class Watch extends core_1.Client {
|
|
|
308
296
|
}
|
|
309
297
|
let startTime = Date.now();
|
|
310
298
|
if ((0, types_1.isPlainObject)(watch)) {
|
|
311
|
-
const
|
|
299
|
+
const reload = watch.reload;
|
|
312
300
|
id = watch.id;
|
|
313
301
|
if (watch.main) {
|
|
314
302
|
main = item;
|
|
315
303
|
}
|
|
316
|
-
if (start) {
|
|
317
|
-
const offset = (0, types_1.parseTime)(start);
|
|
304
|
+
if (watch.start) {
|
|
305
|
+
const offset = (0, types_1.parseTime)(watch.start);
|
|
318
306
|
if (offset > 0) {
|
|
319
307
|
startTime += offset;
|
|
320
308
|
}
|
|
321
309
|
}
|
|
322
|
-
if (
|
|
323
|
-
expires = (0, types_1.parseExpires)(
|
|
310
|
+
if (watch.expires) {
|
|
311
|
+
expires = (0, types_1.parseExpires)(watch.expires, startTime);
|
|
312
|
+
}
|
|
313
|
+
if (watch.recursive) {
|
|
314
|
+
recursive = true;
|
|
324
315
|
}
|
|
325
316
|
if (reload && (socketId = reload.socketId)) {
|
|
326
317
|
({ port, module: hot, always } = reload);
|
|
327
318
|
if (reload.secure) {
|
|
328
|
-
const key = this
|
|
329
|
-
const cert = this
|
|
319
|
+
const key = this.#tlsKey;
|
|
320
|
+
const cert = this.#tlsCert;
|
|
330
321
|
if (key && cert) {
|
|
331
|
-
wss = Watch.createServer(port ||= this.securePort, { ca: this
|
|
322
|
+
wss = Watch.createServer(port ||= this.securePort, { ca: this.#ca, key, cert, passphrase: this.#tlsPassphrase, version: this.#tlsVersion, ciphers: this.#ciphers, config: this.#tlsConfig });
|
|
332
323
|
}
|
|
333
324
|
secure = true;
|
|
334
325
|
}
|
|
@@ -348,7 +339,7 @@ class Watch extends core_1.Client {
|
|
|
348
339
|
}
|
|
349
340
|
const interval = getInterval(item) || watchInterval || this.interval;
|
|
350
341
|
const watching = (uri, esm) => {
|
|
351
|
-
const group = new filegroup_1(uri, main ? assets : items, startTime, this.willAbort("(watch)"));
|
|
342
|
+
const group = new filegroup_1(uri, main ? assets : items, startTime, this.willAbort("(watch)"), recursive);
|
|
352
343
|
group.add(expires, socketId, id);
|
|
353
344
|
if (main) {
|
|
354
345
|
group.main = main;
|
|
@@ -549,7 +540,7 @@ class Watch extends core_1.Client {
|
|
|
549
540
|
}
|
|
550
541
|
})
|
|
551
542
|
.catch((err) => {
|
|
552
|
-
|
|
543
|
+
this.#sendFatalError(err, HTTP_MAP, target);
|
|
553
544
|
client?.destroy();
|
|
554
545
|
});
|
|
555
546
|
}).call(this);
|
|
@@ -557,13 +548,34 @@ class Watch extends core_1.Client {
|
|
|
557
548
|
}
|
|
558
549
|
else if (esm || path.isAbsolute(uri = core_1.Client.resolveFile(uri)) && this.canRead(uri, { hostPermissionOnly: !!this.host })) {
|
|
559
550
|
const pre = checkPreceding(DISK_MAP);
|
|
551
|
+
const options = {};
|
|
552
|
+
let src = uri;
|
|
553
|
+
if (group.matchRecursive(uri)) {
|
|
554
|
+
src = path.dirname(uri);
|
|
555
|
+
for (const pathname in this._recursiveMap) {
|
|
556
|
+
if (src === pathname || src.startsWith(pathname + path.sep)) {
|
|
557
|
+
const parent = this._recursiveMap[pathname].get(group);
|
|
558
|
+
if (parent) {
|
|
559
|
+
parent.push(uri);
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
(this._recursiveMap[pathname] = new Map()).set(group, [uri]);
|
|
563
|
+
}
|
|
564
|
+
return 4;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
if (pre === undefined) {
|
|
568
|
+
(this._recursiveMap[src] = new Map()).set(group, [uri]);
|
|
569
|
+
options.recursive = true;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
560
572
|
if (pre !== undefined) {
|
|
561
573
|
return pre;
|
|
562
574
|
}
|
|
563
575
|
let ptime = 0;
|
|
564
|
-
target.watcher = fs.watch(
|
|
576
|
+
target.watcher = fs.watch(src, options, (event, filename) => {
|
|
565
577
|
if (this.aborted || group.aborted) {
|
|
566
|
-
|
|
578
|
+
this.#sendFatalError((0, types_1.createAbortError)(), DISK_MAP, target);
|
|
567
579
|
return;
|
|
568
580
|
}
|
|
569
581
|
const map = DISK_MAP.get(uri);
|
|
@@ -573,6 +585,11 @@ class Watch extends core_1.Client {
|
|
|
573
585
|
try {
|
|
574
586
|
const mtime = Math.floor(fs.statSync(uri).mtimeMs);
|
|
575
587
|
if (mtime > ptime) {
|
|
588
|
+
ptime = mtime + types_1.THRESHOLD.WATCH_CHANGE;
|
|
589
|
+
if (filename && options.recursive && !group.matchRecursive(path.join(src, filename))) {
|
|
590
|
+
this.formatMessage(16, 'WATCH', ['File modification ignored', 'recursive'], path.join(src, filename), { titleColor: 'yellow' });
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
576
593
|
for (const [key, input] of map) {
|
|
577
594
|
const value = input.value;
|
|
578
595
|
if (value.expired) {
|
|
@@ -593,7 +610,6 @@ class Watch extends core_1.Client {
|
|
|
593
610
|
});
|
|
594
611
|
}
|
|
595
612
|
}
|
|
596
|
-
ptime = mtime + types_1.THRESHOLD.WATCH_CHANGE;
|
|
597
613
|
}
|
|
598
614
|
break;
|
|
599
615
|
}
|
|
@@ -602,6 +618,9 @@ class Watch extends core_1.Client {
|
|
|
602
618
|
}
|
|
603
619
|
}
|
|
604
620
|
case 'rename':
|
|
621
|
+
if (event === 'rename' && group.recursive) {
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
605
624
|
map?.clear();
|
|
606
625
|
this.watchExpired(DISK_MAP, group, event === 'rename' ? 'File renamed: ' + filename : undefined);
|
|
607
626
|
abortTimeout(target);
|
|
@@ -617,11 +636,11 @@ class Watch extends core_1.Client {
|
|
|
617
636
|
};
|
|
618
637
|
if ((0, types_1.isArray)(sourceFiles) && (sourceFiles = sourceFiles.filter(file => this.canRead(file, { hostPermissionOnly: !!this.host }))).length > 0) {
|
|
619
638
|
let index = 0;
|
|
620
|
-
for (const file of new Set(sourceFiles)) {
|
|
639
|
+
for (const file of Array.from(new Set(sourceFiles)).sort((a, b) => a.length - b.length)) {
|
|
621
640
|
if (index++ > 0) {
|
|
622
641
|
watching(file, true);
|
|
623
642
|
}
|
|
624
|
-
else if ((status = watching(watched = file, true)) > 0) {
|
|
643
|
+
else if ((status = watching(watched = file, true)) > 0 && status < 4) {
|
|
625
644
|
break;
|
|
626
645
|
}
|
|
627
646
|
}
|
|
@@ -632,6 +651,9 @@ class Watch extends core_1.Client {
|
|
|
632
651
|
else {
|
|
633
652
|
continue;
|
|
634
653
|
}
|
|
654
|
+
if (status === 4) {
|
|
655
|
+
continue;
|
|
656
|
+
}
|
|
635
657
|
if (status > 0) {
|
|
636
658
|
if (message ||= getErrorMessage(item, status)) {
|
|
637
659
|
this.formatFail((16 | (status === 2 ? 8192 : 0)), 'WATCH', ["Unable to watch file", watched && path.basename(watched)], (0, types_1.errorValue)(message, watched), { fatal: false });
|
|
@@ -644,7 +666,18 @@ class Watch extends core_1.Client {
|
|
|
644
666
|
}
|
|
645
667
|
}
|
|
646
668
|
async modified(watch) {
|
|
647
|
-
this.
|
|
669
|
+
const recursive = this.getRecursiveFiles(watch);
|
|
670
|
+
let message = "File modified", uri = watch.uri;
|
|
671
|
+
if (recursive.length > 0) {
|
|
672
|
+
const time = this.#recursiveTime.get(watch) || 0;
|
|
673
|
+
if (time + types_1.THRESHOLD.WATCH_RECURSIVE_CHANGE >= Date.now()) {
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
message = "Directory was modified";
|
|
677
|
+
uri = path.dirname(watch.uri);
|
|
678
|
+
this.#recursiveTime.set(watch, Date.now());
|
|
679
|
+
}
|
|
680
|
+
this.formatMessage(16, 'WATCH', message, uri, { ...core_1.Client.LOG_STYLE_WARN });
|
|
648
681
|
const { host, assets } = this;
|
|
649
682
|
let items, sanitize = false;
|
|
650
683
|
if (watch.main) {
|
|
@@ -696,31 +729,32 @@ class Watch extends core_1.Client {
|
|
|
696
729
|
catch {
|
|
697
730
|
}
|
|
698
731
|
}
|
|
699
|
-
if (manager) {
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
const document = manager.find(instance.moduleName);
|
|
710
|
-
if (document) {
|
|
711
|
-
document.dataSource = result.dataSource;
|
|
712
|
-
}
|
|
713
|
-
}
|
|
732
|
+
if (!manager) {
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
if (host && watch.document) {
|
|
736
|
+
for (const { instance } of host.Document) {
|
|
737
|
+
if (host.hasDocument(instance, watch.document)) {
|
|
738
|
+
const result = instance.watchInit?.(watch, items, sanitize);
|
|
739
|
+
if (result) {
|
|
740
|
+
if ((0, types_1.isArray)(result.using)) {
|
|
741
|
+
manager.using(...result.using);
|
|
714
742
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
743
|
+
if (Array.isArray(result.dataSource)) {
|
|
744
|
+
const document = manager.find(instance.moduleName);
|
|
745
|
+
if (document) {
|
|
746
|
+
document.dataSource = result.dataSource;
|
|
747
|
+
}
|
|
718
748
|
}
|
|
719
749
|
}
|
|
750
|
+
const listener = instance.watchModified?.(watch, items, recursive);
|
|
751
|
+
if (typeof listener === 'function') {
|
|
752
|
+
manager.on('end', listener);
|
|
753
|
+
}
|
|
720
754
|
}
|
|
721
755
|
}
|
|
722
|
-
return await manager.start();
|
|
723
756
|
}
|
|
757
|
+
return await manager.start();
|
|
724
758
|
}
|
|
725
759
|
catch (err) {
|
|
726
760
|
this.writeFail(["Unknown", watch.url?.pathname || path.basename(watch.uri)], err);
|
|
@@ -734,16 +768,16 @@ class Watch extends core_1.Client {
|
|
|
734
768
|
this.setCA(ca);
|
|
735
769
|
}
|
|
736
770
|
if (request_1.isCert(key) || core_1.Client.isPath(key = path.resolve(key)) && this.canRead(key, { ownPermissionOnly: true })) {
|
|
737
|
-
this
|
|
771
|
+
this.#tlsKey = key;
|
|
738
772
|
}
|
|
739
773
|
if (request_1.isCert(cert) || core_1.Client.isPath(cert = path.resolve(cert)) && this.canRead(cert, { ownPermissionOnly: true })) {
|
|
740
|
-
this
|
|
774
|
+
this.#tlsCert = cert;
|
|
741
775
|
}
|
|
742
776
|
if ((0, types_1.isString)(passphrase)) {
|
|
743
|
-
this
|
|
777
|
+
this.#tlsPassphrase = passphrase;
|
|
744
778
|
}
|
|
745
779
|
if ((0, types_1.isString)(ciphers)) {
|
|
746
|
-
this
|
|
780
|
+
this.#ciphers = ciphers;
|
|
747
781
|
}
|
|
748
782
|
if (!(0, types_1.isPlainObject)(config)) {
|
|
749
783
|
config = undefined;
|
|
@@ -762,33 +796,45 @@ class Watch extends core_1.Client {
|
|
|
762
796
|
version = undefined;
|
|
763
797
|
break;
|
|
764
798
|
}
|
|
765
|
-
this
|
|
766
|
-
this
|
|
799
|
+
this.#tlsConfig = config;
|
|
800
|
+
this.#tlsVersion = version;
|
|
767
801
|
return this.hasSecureProtocol();
|
|
768
802
|
}
|
|
769
803
|
setCA(value) {
|
|
770
804
|
if ((0, types_1.isString)(value) && core_1.Client.isPath(value = path.resolve(value = value.trim())) && this.canRead(value, { ownPermissionOnly: true })) {
|
|
771
|
-
this
|
|
805
|
+
this.#ca = value;
|
|
772
806
|
return true;
|
|
773
807
|
}
|
|
774
808
|
return false;
|
|
775
809
|
}
|
|
776
810
|
setSSLKey(value) {
|
|
777
|
-
this
|
|
778
|
-
this
|
|
779
|
-
return !!(this
|
|
811
|
+
this.#tlsConfig = { secureProtocol: 'SSLv23_method' };
|
|
812
|
+
this.#tlsVersion = undefined;
|
|
813
|
+
return !!(this.#tlsKey = request_1.readTLSKey(value, true));
|
|
780
814
|
}
|
|
781
815
|
setSSLCert(value) {
|
|
782
|
-
return !!(this
|
|
816
|
+
return !!(this.#tlsCert = request_1.readTLSCert(value, true));
|
|
783
817
|
}
|
|
784
818
|
hasSecureProtocol() {
|
|
785
|
-
return !!this
|
|
819
|
+
return !!this.#tlsKey && !!this.#tlsCert;
|
|
786
820
|
}
|
|
787
821
|
willAbort(value) {
|
|
788
822
|
return this.host ? this.host.willAbort(value) : value === "(watch)";
|
|
789
823
|
}
|
|
824
|
+
getRecursiveFiles(watch) {
|
|
825
|
+
const result = [];
|
|
826
|
+
if (watch.recursive) {
|
|
827
|
+
for (const pathname in this._recursiveMap) {
|
|
828
|
+
const files = this._recursiveMap[pathname].get(watch);
|
|
829
|
+
if (files) {
|
|
830
|
+
result.push([pathname, files]);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
return result;
|
|
835
|
+
}
|
|
790
836
|
watchExpired(map, target, message = "Expired") {
|
|
791
|
-
this.formatMessage(16, 'WATCH', [message, target.startTime ? 'since ' + formatDate(target.startTime) : ''], target.uri, { titleColor: 'grey' });
|
|
837
|
+
this.formatMessage(16, 'WATCH', [message, target.startTime ? 'since ' + formatDate(target.startTime) : ''], this.getRecursiveFiles(target).length > 0 ? path.dirname(target.uri) : target.uri, { titleColor: 'grey' });
|
|
792
838
|
const data = map.get(target.uri);
|
|
793
839
|
if (!data?.size) {
|
|
794
840
|
map.delete(target.uri);
|
|
@@ -796,6 +842,12 @@ class Watch extends core_1.Client {
|
|
|
796
842
|
}
|
|
797
843
|
return false;
|
|
798
844
|
}
|
|
845
|
+
#sendFatalError(err, map, target) {
|
|
846
|
+
const uri = target.value.uri;
|
|
847
|
+
map.delete(uri);
|
|
848
|
+
abortTimeout(target);
|
|
849
|
+
this.writeFail(["Unable to watch file", uri], err, 16);
|
|
850
|
+
}
|
|
799
851
|
set host(value) {
|
|
800
852
|
super.host = value;
|
|
801
853
|
if ((0, types_1.isArray)(value?.assets)) {
|
|
@@ -818,29 +870,27 @@ class Watch extends core_1.Client {
|
|
|
818
870
|
}
|
|
819
871
|
set interval(value) {
|
|
820
872
|
if (value > 0) {
|
|
821
|
-
this
|
|
873
|
+
this.#internal = value;
|
|
822
874
|
}
|
|
823
875
|
}
|
|
824
876
|
get interval() {
|
|
825
|
-
return this
|
|
877
|
+
return this.#internal;
|
|
826
878
|
}
|
|
827
879
|
set port(value) {
|
|
828
880
|
if (value > 0) {
|
|
829
|
-
this
|
|
881
|
+
this.#port = value;
|
|
830
882
|
}
|
|
831
883
|
}
|
|
832
884
|
get port() {
|
|
833
|
-
return this
|
|
885
|
+
return this.#port;
|
|
834
886
|
}
|
|
835
887
|
set securePort(value) {
|
|
836
888
|
if (value > 0) {
|
|
837
|
-
this
|
|
889
|
+
this.#securePort = value;
|
|
838
890
|
}
|
|
839
891
|
}
|
|
840
892
|
get securePort() {
|
|
841
|
-
return this
|
|
893
|
+
return this.#securePort;
|
|
842
894
|
}
|
|
843
895
|
}
|
|
844
|
-
_a = kInterval, _b = kPort, _c = kSecurePort, _d = kCa, _e = kCiphers, _f = kTlsKey, _g = kTlsCert, _h = kTlsPassphrase, _j = kTlsVersion, _k = kTlsConfig;
|
|
845
|
-
Watch.PROCESS_TIMEOUT = 5 * 1000;
|
|
846
896
|
module.exports = Watch;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e-mc/watch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Watch constructor for E-mc.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"license": "BSD-3-Clause",
|
|
21
21
|
"homepage": "https://github.com/anpham6/e-mc#readme",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@e-mc/core": "0.
|
|
24
|
-
"@e-mc/request": "0.
|
|
25
|
-
"@e-mc/types": "0.
|
|
23
|
+
"@e-mc/core": "0.12.0",
|
|
24
|
+
"@e-mc/request": "0.12.0",
|
|
25
|
+
"@e-mc/types": "0.12.0",
|
|
26
26
|
"picomatch": "^4.0.2",
|
|
27
27
|
"ws": "^8.18.1"
|
|
28
28
|
}
|