@e-mc/watch 0.11.8 → 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 +141 -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;
|
|
@@ -293,7 +279,7 @@ class Watch extends core_1.Client {
|
|
|
293
279
|
}
|
|
294
280
|
if (!watch && localUri && !(watch = settings[localUri])) {
|
|
295
281
|
const pathname = core_1.Client.PLATFORM_WIN32 ? core_1.Client.toPosix(localUri) : localUri;
|
|
296
|
-
const options = core_1.Client.PLATFORM_WIN32 ? { nocase: true, windows: true, posixSlashes: true } : {};
|
|
282
|
+
const options = core_1.Client.PLATFORM_WIN32 ? { nocase: true, matchBase: true, windows: true, posixSlashes: true } : { matchBase: true };
|
|
297
283
|
for (const pattern in settings) {
|
|
298
284
|
if ((0, types_1.hasGlob)(pattern) && pm.isMatch(pathname, pattern, options) && (watch = settings[pattern])) {
|
|
299
285
|
break;
|
|
@@ -310,27 +296,30 @@ class Watch extends core_1.Client {
|
|
|
310
296
|
}
|
|
311
297
|
let startTime = Date.now();
|
|
312
298
|
if ((0, types_1.isPlainObject)(watch)) {
|
|
313
|
-
const
|
|
299
|
+
const reload = watch.reload;
|
|
314
300
|
id = watch.id;
|
|
315
301
|
if (watch.main) {
|
|
316
302
|
main = item;
|
|
317
303
|
}
|
|
318
|
-
if (start) {
|
|
319
|
-
const offset = (0, types_1.parseTime)(start);
|
|
304
|
+
if (watch.start) {
|
|
305
|
+
const offset = (0, types_1.parseTime)(watch.start);
|
|
320
306
|
if (offset > 0) {
|
|
321
307
|
startTime += offset;
|
|
322
308
|
}
|
|
323
309
|
}
|
|
324
|
-
if (
|
|
325
|
-
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;
|
|
326
315
|
}
|
|
327
316
|
if (reload && (socketId = reload.socketId)) {
|
|
328
317
|
({ port, module: hot, always } = reload);
|
|
329
318
|
if (reload.secure) {
|
|
330
|
-
const key = this
|
|
331
|
-
const cert = this
|
|
319
|
+
const key = this.#tlsKey;
|
|
320
|
+
const cert = this.#tlsCert;
|
|
332
321
|
if (key && cert) {
|
|
333
|
-
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 });
|
|
334
323
|
}
|
|
335
324
|
secure = true;
|
|
336
325
|
}
|
|
@@ -350,7 +339,7 @@ class Watch extends core_1.Client {
|
|
|
350
339
|
}
|
|
351
340
|
const interval = getInterval(item) || watchInterval || this.interval;
|
|
352
341
|
const watching = (uri, esm) => {
|
|
353
|
-
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);
|
|
354
343
|
group.add(expires, socketId, id);
|
|
355
344
|
if (main) {
|
|
356
345
|
group.main = main;
|
|
@@ -551,7 +540,7 @@ class Watch extends core_1.Client {
|
|
|
551
540
|
}
|
|
552
541
|
})
|
|
553
542
|
.catch((err) => {
|
|
554
|
-
|
|
543
|
+
this.#sendFatalError(err, HTTP_MAP, target);
|
|
555
544
|
client?.destroy();
|
|
556
545
|
});
|
|
557
546
|
}).call(this);
|
|
@@ -559,13 +548,34 @@ class Watch extends core_1.Client {
|
|
|
559
548
|
}
|
|
560
549
|
else if (esm || path.isAbsolute(uri = core_1.Client.resolveFile(uri)) && this.canRead(uri, { hostPermissionOnly: !!this.host })) {
|
|
561
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
|
+
}
|
|
562
572
|
if (pre !== undefined) {
|
|
563
573
|
return pre;
|
|
564
574
|
}
|
|
565
575
|
let ptime = 0;
|
|
566
|
-
target.watcher = fs.watch(
|
|
576
|
+
target.watcher = fs.watch(src, options, (event, filename) => {
|
|
567
577
|
if (this.aborted || group.aborted) {
|
|
568
|
-
|
|
578
|
+
this.#sendFatalError((0, types_1.createAbortError)(), DISK_MAP, target);
|
|
569
579
|
return;
|
|
570
580
|
}
|
|
571
581
|
const map = DISK_MAP.get(uri);
|
|
@@ -575,6 +585,11 @@ class Watch extends core_1.Client {
|
|
|
575
585
|
try {
|
|
576
586
|
const mtime = Math.floor(fs.statSync(uri).mtimeMs);
|
|
577
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
|
+
}
|
|
578
593
|
for (const [key, input] of map) {
|
|
579
594
|
const value = input.value;
|
|
580
595
|
if (value.expired) {
|
|
@@ -595,7 +610,6 @@ class Watch extends core_1.Client {
|
|
|
595
610
|
});
|
|
596
611
|
}
|
|
597
612
|
}
|
|
598
|
-
ptime = mtime + types_1.THRESHOLD.WATCH_CHANGE;
|
|
599
613
|
}
|
|
600
614
|
break;
|
|
601
615
|
}
|
|
@@ -604,6 +618,9 @@ class Watch extends core_1.Client {
|
|
|
604
618
|
}
|
|
605
619
|
}
|
|
606
620
|
case 'rename':
|
|
621
|
+
if (event === 'rename' && group.recursive) {
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
607
624
|
map?.clear();
|
|
608
625
|
this.watchExpired(DISK_MAP, group, event === 'rename' ? 'File renamed: ' + filename : undefined);
|
|
609
626
|
abortTimeout(target);
|
|
@@ -619,11 +636,11 @@ class Watch extends core_1.Client {
|
|
|
619
636
|
};
|
|
620
637
|
if ((0, types_1.isArray)(sourceFiles) && (sourceFiles = sourceFiles.filter(file => this.canRead(file, { hostPermissionOnly: !!this.host }))).length > 0) {
|
|
621
638
|
let index = 0;
|
|
622
|
-
for (const file of new Set(sourceFiles)) {
|
|
639
|
+
for (const file of Array.from(new Set(sourceFiles)).sort((a, b) => a.length - b.length)) {
|
|
623
640
|
if (index++ > 0) {
|
|
624
641
|
watching(file, true);
|
|
625
642
|
}
|
|
626
|
-
else if ((status = watching(watched = file, true)) > 0) {
|
|
643
|
+
else if ((status = watching(watched = file, true)) > 0 && status < 4) {
|
|
627
644
|
break;
|
|
628
645
|
}
|
|
629
646
|
}
|
|
@@ -634,6 +651,9 @@ class Watch extends core_1.Client {
|
|
|
634
651
|
else {
|
|
635
652
|
continue;
|
|
636
653
|
}
|
|
654
|
+
if (status === 4) {
|
|
655
|
+
continue;
|
|
656
|
+
}
|
|
637
657
|
if (status > 0) {
|
|
638
658
|
if (message ||= getErrorMessage(item, status)) {
|
|
639
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 });
|
|
@@ -646,7 +666,18 @@ class Watch extends core_1.Client {
|
|
|
646
666
|
}
|
|
647
667
|
}
|
|
648
668
|
async modified(watch) {
|
|
649
|
-
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 });
|
|
650
681
|
const { host, assets } = this;
|
|
651
682
|
let items, sanitize = false;
|
|
652
683
|
if (watch.main) {
|
|
@@ -698,31 +729,32 @@ class Watch extends core_1.Client {
|
|
|
698
729
|
catch {
|
|
699
730
|
}
|
|
700
731
|
}
|
|
701
|
-
if (manager) {
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
const document = manager.find(instance.moduleName);
|
|
712
|
-
if (document) {
|
|
713
|
-
document.dataSource = result.dataSource;
|
|
714
|
-
}
|
|
715
|
-
}
|
|
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);
|
|
716
742
|
}
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
743
|
+
if (Array.isArray(result.dataSource)) {
|
|
744
|
+
const document = manager.find(instance.moduleName);
|
|
745
|
+
if (document) {
|
|
746
|
+
document.dataSource = result.dataSource;
|
|
747
|
+
}
|
|
720
748
|
}
|
|
721
749
|
}
|
|
750
|
+
const listener = instance.watchModified?.(watch, items, recursive);
|
|
751
|
+
if (typeof listener === 'function') {
|
|
752
|
+
manager.on('end', listener);
|
|
753
|
+
}
|
|
722
754
|
}
|
|
723
755
|
}
|
|
724
|
-
return await manager.start();
|
|
725
756
|
}
|
|
757
|
+
return await manager.start();
|
|
726
758
|
}
|
|
727
759
|
catch (err) {
|
|
728
760
|
this.writeFail(["Unknown", watch.url?.pathname || path.basename(watch.uri)], err);
|
|
@@ -736,16 +768,16 @@ class Watch extends core_1.Client {
|
|
|
736
768
|
this.setCA(ca);
|
|
737
769
|
}
|
|
738
770
|
if (request_1.isCert(key) || core_1.Client.isPath(key = path.resolve(key)) && this.canRead(key, { ownPermissionOnly: true })) {
|
|
739
|
-
this
|
|
771
|
+
this.#tlsKey = key;
|
|
740
772
|
}
|
|
741
773
|
if (request_1.isCert(cert) || core_1.Client.isPath(cert = path.resolve(cert)) && this.canRead(cert, { ownPermissionOnly: true })) {
|
|
742
|
-
this
|
|
774
|
+
this.#tlsCert = cert;
|
|
743
775
|
}
|
|
744
776
|
if ((0, types_1.isString)(passphrase)) {
|
|
745
|
-
this
|
|
777
|
+
this.#tlsPassphrase = passphrase;
|
|
746
778
|
}
|
|
747
779
|
if ((0, types_1.isString)(ciphers)) {
|
|
748
|
-
this
|
|
780
|
+
this.#ciphers = ciphers;
|
|
749
781
|
}
|
|
750
782
|
if (!(0, types_1.isPlainObject)(config)) {
|
|
751
783
|
config = undefined;
|
|
@@ -764,33 +796,45 @@ class Watch extends core_1.Client {
|
|
|
764
796
|
version = undefined;
|
|
765
797
|
break;
|
|
766
798
|
}
|
|
767
|
-
this
|
|
768
|
-
this
|
|
799
|
+
this.#tlsConfig = config;
|
|
800
|
+
this.#tlsVersion = version;
|
|
769
801
|
return this.hasSecureProtocol();
|
|
770
802
|
}
|
|
771
803
|
setCA(value) {
|
|
772
804
|
if ((0, types_1.isString)(value) && core_1.Client.isPath(value = path.resolve(value = value.trim())) && this.canRead(value, { ownPermissionOnly: true })) {
|
|
773
|
-
this
|
|
805
|
+
this.#ca = value;
|
|
774
806
|
return true;
|
|
775
807
|
}
|
|
776
808
|
return false;
|
|
777
809
|
}
|
|
778
810
|
setSSLKey(value) {
|
|
779
|
-
this
|
|
780
|
-
this
|
|
781
|
-
return !!(this
|
|
811
|
+
this.#tlsConfig = { secureProtocol: 'SSLv23_method' };
|
|
812
|
+
this.#tlsVersion = undefined;
|
|
813
|
+
return !!(this.#tlsKey = request_1.readTLSKey(value, true));
|
|
782
814
|
}
|
|
783
815
|
setSSLCert(value) {
|
|
784
|
-
return !!(this
|
|
816
|
+
return !!(this.#tlsCert = request_1.readTLSCert(value, true));
|
|
785
817
|
}
|
|
786
818
|
hasSecureProtocol() {
|
|
787
|
-
return !!this
|
|
819
|
+
return !!this.#tlsKey && !!this.#tlsCert;
|
|
788
820
|
}
|
|
789
821
|
willAbort(value) {
|
|
790
822
|
return this.host ? this.host.willAbort(value) : value === "(watch)";
|
|
791
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
|
+
}
|
|
792
836
|
watchExpired(map, target, message = "Expired") {
|
|
793
|
-
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' });
|
|
794
838
|
const data = map.get(target.uri);
|
|
795
839
|
if (!data?.size) {
|
|
796
840
|
map.delete(target.uri);
|
|
@@ -798,6 +842,12 @@ class Watch extends core_1.Client {
|
|
|
798
842
|
}
|
|
799
843
|
return false;
|
|
800
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
|
+
}
|
|
801
851
|
set host(value) {
|
|
802
852
|
super.host = value;
|
|
803
853
|
if ((0, types_1.isArray)(value?.assets)) {
|
|
@@ -820,29 +870,27 @@ class Watch extends core_1.Client {
|
|
|
820
870
|
}
|
|
821
871
|
set interval(value) {
|
|
822
872
|
if (value > 0) {
|
|
823
|
-
this
|
|
873
|
+
this.#internal = value;
|
|
824
874
|
}
|
|
825
875
|
}
|
|
826
876
|
get interval() {
|
|
827
|
-
return this
|
|
877
|
+
return this.#internal;
|
|
828
878
|
}
|
|
829
879
|
set port(value) {
|
|
830
880
|
if (value > 0) {
|
|
831
|
-
this
|
|
881
|
+
this.#port = value;
|
|
832
882
|
}
|
|
833
883
|
}
|
|
834
884
|
get port() {
|
|
835
|
-
return this
|
|
885
|
+
return this.#port;
|
|
836
886
|
}
|
|
837
887
|
set securePort(value) {
|
|
838
888
|
if (value > 0) {
|
|
839
|
-
this
|
|
889
|
+
this.#securePort = value;
|
|
840
890
|
}
|
|
841
891
|
}
|
|
842
892
|
get securePort() {
|
|
843
|
-
return this
|
|
893
|
+
return this.#securePort;
|
|
844
894
|
}
|
|
845
895
|
}
|
|
846
|
-
_a = kInterval, _b = kPort, _c = kSecurePort, _d = kCa, _e = kCiphers, _f = kTlsKey, _g = kTlsCert, _h = kTlsPassphrase, _j = kTlsVersion, _k = kTlsConfig;
|
|
847
|
-
Watch.PROCESS_TIMEOUT = 5 * 1000;
|
|
848
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
|
}
|