@e-mc/watch 0.8.5 → 0.8.7
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/LICENSE +8 -4
- package/README.md +63 -2
- package/filegroup/index.js +4 -4
- package/index.js +35 -44
- package/package.json +5 -5
package/LICENSE
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
Copyright 2024
|
|
1
|
+
Copyright 2024 An Pham
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
8
|
+
|
|
9
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
10
|
+
|
|
11
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
CHANGED
|
@@ -1,7 +1,68 @@
|
|
|
1
1
|
# @e-mc/watch
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
* NodeJS 14
|
|
4
|
+
* ES2020
|
|
5
|
+
|
|
6
|
+
## General Usage
|
|
7
|
+
|
|
8
|
+
* [Read the Docs](https://e-mc.readthedocs.io)
|
|
9
|
+
|
|
10
|
+
## Interface
|
|
11
|
+
|
|
12
|
+
- https://www.unpkg.com/@e-mc/types@0.8.7/lib/index.d.ts
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import type { IFileManager, ModuleConstructor } from "./index";
|
|
16
|
+
import type { ExternalAsset } from "./asset";
|
|
17
|
+
import type { IClient, IPermission } from "./core";
|
|
18
|
+
import type { FinalizeResult, PostFinalizeCallback } from "./filemanager";
|
|
19
|
+
import type { WatchModule } from "./settings";
|
|
20
|
+
import type { IFileGroup, ModifiedPostFinalizeListener, SecureOptions } from "./watch";
|
|
21
|
+
|
|
22
|
+
import type * as ws from "ws";
|
|
23
|
+
|
|
24
|
+
interface IWatch extends IClient<IFileManager, WatchModule, ModifiedPostFinalizeListener> {
|
|
25
|
+
connectTimeout: number;
|
|
26
|
+
start(assets: ExternalAsset[], permission?: IPermission | null): void;
|
|
27
|
+
modified(watch: IFileGroup<ExternalAsset>): Promise<FinalizeResult | void>;
|
|
28
|
+
configureServer(options: SecureOptions): boolean;
|
|
29
|
+
setCA(value: string): boolean;
|
|
30
|
+
setSSLKey(value: string): boolean;
|
|
31
|
+
setSSLCert(value: string): boolean;
|
|
32
|
+
hasSecureProtocol(): boolean;
|
|
33
|
+
whenModified?(assets: ExternalAsset[], postFinalize: PostFinalizeCallback): IFileManager;
|
|
34
|
+
whenModified?(assets: ExternalAsset[], sanitize?: boolean | PostFinalizeCallback, postFinalize?: PostFinalizeCallback): IFileManager;
|
|
35
|
+
set assets(value: ExternalAsset[]);
|
|
36
|
+
get assets(): ExternalAsset[];
|
|
37
|
+
set interval(value);
|
|
38
|
+
get interval(): number;
|
|
39
|
+
set port(value);
|
|
40
|
+
get port(): number;
|
|
41
|
+
set securePort(value);
|
|
42
|
+
get securePort(): number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface WatchConstructor extends ModuleConstructor {
|
|
46
|
+
createServer(port: number, active: boolean): ws.Server | null;
|
|
47
|
+
createServer(port: number, secure?: SecureOptions | null, active?: boolean): ws.Server | null;
|
|
48
|
+
shutdown(): void;
|
|
49
|
+
setTimeout(value: number | string): void;
|
|
50
|
+
checkTimeout(client: ws): boolean;
|
|
51
|
+
readonly prototype: IWatch;
|
|
52
|
+
new(module?: WatchModule): IWatch;
|
|
53
|
+
/* @deprecated */
|
|
54
|
+
new(interval?: number, port?: number, securePort?: number, extensions?: unknown[]): IWatch;
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## References
|
|
59
|
+
|
|
60
|
+
- https://www.unpkg.com/@e-mc/types@0.8.7/lib/asset.d.ts
|
|
61
|
+
- https://www.unpkg.com/@e-mc/types@0.8.7/lib/core.d.ts
|
|
62
|
+
- https://www.unpkg.com/@e-mc/types@0.8.7/lib/filemanager.d.ts
|
|
63
|
+
- https://www.unpkg.com/@e-mc/types@0.8.7/lib/settings.d.ts
|
|
64
|
+
- https://www.unpkg.com/@e-mc/types@0.8.7/lib/watch.d.ts
|
|
4
65
|
|
|
5
66
|
## LICENSE
|
|
6
67
|
|
|
7
|
-
|
|
68
|
+
BSD 3-Clause
|
package/filegroup/index.js
CHANGED
|
@@ -3,8 +3,8 @@ var _a, _b, _c, _d, _e, _f;
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const util = require("util");
|
|
5
5
|
const ws = require("ws");
|
|
6
|
-
const types_1 = require("
|
|
7
|
-
const core_1 = require("
|
|
6
|
+
const types_1 = require("@e-mc/types");
|
|
7
|
+
const core_1 = require("@e-mc/core");
|
|
8
8
|
const kServer = Symbol('server');
|
|
9
9
|
const kStarted = Symbol('started');
|
|
10
10
|
const kPaused = Symbol('paused');
|
|
@@ -151,7 +151,7 @@ class FileGroup extends core_1.AbortComponent {
|
|
|
151
151
|
set related(value) {
|
|
152
152
|
this._related = value.map(item => {
|
|
153
153
|
item = FileGroup.cloneAsset(item);
|
|
154
|
-
item.flags = 1
|
|
154
|
+
item.flags = 1;
|
|
155
155
|
return item;
|
|
156
156
|
});
|
|
157
157
|
}
|
|
@@ -206,7 +206,7 @@ class FileGroup extends core_1.AbortComponent {
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
_a = kServer, _b = kStarted, _c = kPaused, _d = kEtag, _e = kLastModified, _f = kSockets;
|
|
209
|
-
FileGroup.CONNECTION_TIMEOUT = 10 * 60000
|
|
209
|
+
FileGroup.CONNECTION_TIMEOUT = 10 * 60000;
|
|
210
210
|
FileGroup.CLIENT_SESSION = new Map();
|
|
211
211
|
exports.default = FileGroup;
|
|
212
212
|
|
package/index.js
CHANGED
|
@@ -6,11 +6,11 @@ const fs = require("fs");
|
|
|
6
6
|
const https = require("https");
|
|
7
7
|
const ws = require("ws");
|
|
8
8
|
const pm = require("picomatch");
|
|
9
|
-
const util_1 = require("
|
|
10
|
-
const types_1 = require("
|
|
11
|
-
const core_1 = require("
|
|
12
|
-
const request_1 = require("
|
|
13
|
-
const filegroup_1 = require("
|
|
9
|
+
const util_1 = require("@e-mc/request/util");
|
|
10
|
+
const types_1 = require("@e-mc/types");
|
|
11
|
+
const core_1 = require("@e-mc/core");
|
|
12
|
+
const request_1 = require("@e-mc/request");
|
|
13
|
+
const filegroup_1 = require("@e-mc/watch/filegroup");
|
|
14
14
|
const kInterval = Symbol('interval');
|
|
15
15
|
const kPort = Symbol('port');
|
|
16
16
|
const kSecurePort = Symbol('securePort');
|
|
@@ -26,15 +26,6 @@ const DISK_MAP = new Map();
|
|
|
26
26
|
const PORT_MAP = new Map();
|
|
27
27
|
const SECURE_MAP = new Map();
|
|
28
28
|
let STATE_MAP = new WeakSet();
|
|
29
|
-
function isConnectionTimeout(err) {
|
|
30
|
-
switch (err instanceof Error && err.code) {
|
|
31
|
-
case 'ETIMEDOUT':
|
|
32
|
-
case 'ECONNRESET':
|
|
33
|
-
return true;
|
|
34
|
-
default:
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
29
|
function abortTimeout(group) {
|
|
39
30
|
group.timeout.aborted = true;
|
|
40
31
|
const watcher = group.watcher;
|
|
@@ -116,7 +107,7 @@ class Watch extends core_1.Client {
|
|
|
116
107
|
}
|
|
117
108
|
}
|
|
118
109
|
catch (err) {
|
|
119
|
-
this.writeFail("Unknown"
|
|
110
|
+
this.writeFail("Unknown", err);
|
|
120
111
|
}
|
|
121
112
|
if (!wss) {
|
|
122
113
|
return null;
|
|
@@ -163,8 +154,8 @@ class Watch extends core_1.Client {
|
|
|
163
154
|
this._extensions = [];
|
|
164
155
|
this._hostEvents = [];
|
|
165
156
|
this[_a] = types_1.THRESHOLD.WATCH_INTERVAL;
|
|
166
|
-
this[_b] = 80
|
|
167
|
-
this[_c] = 443
|
|
157
|
+
this[_b] = 80;
|
|
158
|
+
this[_c] = 443;
|
|
168
159
|
this[_d] = '';
|
|
169
160
|
this[_e] = '';
|
|
170
161
|
this[_f] = '';
|
|
@@ -239,7 +230,7 @@ class Watch extends core_1.Client {
|
|
|
239
230
|
other = filegroup_1.default.cloneAsset(other);
|
|
240
231
|
other.watch = { ...watch };
|
|
241
232
|
}
|
|
242
|
-
other.flags &= ~1
|
|
233
|
+
other.flags &= ~1;
|
|
243
234
|
other.invalid = undefined;
|
|
244
235
|
items.push(other);
|
|
245
236
|
}
|
|
@@ -258,10 +249,10 @@ class Watch extends core_1.Client {
|
|
|
258
249
|
const uri = target.value.uri;
|
|
259
250
|
map.delete(uri);
|
|
260
251
|
abortTimeout(target);
|
|
261
|
-
this.writeFail(["Unable to watch file"
|
|
252
|
+
this.writeFail(["Unable to watch file", uri], err, 16);
|
|
262
253
|
};
|
|
263
254
|
const watchExpired = (map, target, message = 'Expired') => {
|
|
264
|
-
this.formatMessage(16
|
|
255
|
+
this.formatMessage(16, 'WATCH', [message, target.startTime ? 'since ' + formatDate(target.startTime) : ''], target.uri, { titleColor: 'grey' });
|
|
265
256
|
const data = map.get(target.uri);
|
|
266
257
|
if (!data?.size) {
|
|
267
258
|
map.delete(target.uri);
|
|
@@ -325,7 +316,7 @@ class Watch extends core_1.Client {
|
|
|
325
316
|
wss = Watch.createServer(port || (port = this.port));
|
|
326
317
|
}
|
|
327
318
|
if (!wss) {
|
|
328
|
-
this.writeFail('Unable to create WebSocket server', (0, types_1.errorMessage)(secure ? 'wss' : 'ws', "Invalid parameters"
|
|
319
|
+
this.writeFail('Unable to create WebSocket server', (0, types_1.errorMessage)(secure ? 'wss' : 'ws', "Invalid parameters", 'port: ' + (port || "Unknown")), 16);
|
|
329
320
|
socketId = undefined;
|
|
330
321
|
port = undefined;
|
|
331
322
|
secure = undefined;
|
|
@@ -337,7 +328,7 @@ class Watch extends core_1.Client {
|
|
|
337
328
|
}
|
|
338
329
|
const interval = getInterval(item) || watchInterval || this.interval;
|
|
339
330
|
const watching = (uri, esm) => {
|
|
340
|
-
const group = new filegroup_1.default(uri, main ? assets : items, startTime, this.willAbort("(watch)"
|
|
331
|
+
const group = new filegroup_1.default(uri, main ? assets : items, startTime, this.willAbort("(watch)"));
|
|
341
332
|
group.add(expires, socketId, id);
|
|
342
333
|
if (main) {
|
|
343
334
|
group.main = main;
|
|
@@ -410,7 +401,7 @@ class Watch extends core_1.Client {
|
|
|
410
401
|
wss.close();
|
|
411
402
|
}
|
|
412
403
|
message = 'Destination already watched @ ' + (current.secure ? 'wss' : 'ws') + '://hostname:' + current.port;
|
|
413
|
-
return 3
|
|
404
|
+
return 3;
|
|
414
405
|
}
|
|
415
406
|
}
|
|
416
407
|
const socket = socketId && current.find(socketId);
|
|
@@ -420,18 +411,18 @@ class Watch extends core_1.Client {
|
|
|
420
411
|
else {
|
|
421
412
|
current.add(expires, socketId, id);
|
|
422
413
|
}
|
|
423
|
-
return 0
|
|
414
|
+
return 0;
|
|
424
415
|
}
|
|
425
416
|
}
|
|
426
417
|
data.set(dest, target);
|
|
427
|
-
return 0
|
|
418
|
+
return 0;
|
|
428
419
|
};
|
|
429
420
|
if (core_1.Client.isFile(uri, 'http/s')) {
|
|
430
421
|
group.url = item.url;
|
|
431
422
|
group.etag = item.etag;
|
|
432
423
|
group.lastModified = item.lastModified;
|
|
433
424
|
if (!group.etag && !group.lastModified) {
|
|
434
|
-
return 1
|
|
425
|
+
return 1;
|
|
435
426
|
}
|
|
436
427
|
if ((status = checkPreceding(HTTP_MAP)) !== undefined) {
|
|
437
428
|
return status;
|
|
@@ -453,7 +444,7 @@ class Watch extends core_1.Client {
|
|
|
453
444
|
return;
|
|
454
445
|
}
|
|
455
446
|
const statusCode = res.statusCode;
|
|
456
|
-
const valid = statusCode >= 200
|
|
447
|
+
const valid = statusCode >= 200 && statusCode < 300;
|
|
457
448
|
const map = HTTP_MAP.get(uri);
|
|
458
449
|
const etag = res.headers.etag;
|
|
459
450
|
const lastModified = res.headers['last-modified'];
|
|
@@ -509,15 +500,15 @@ class Watch extends core_1.Client {
|
|
|
509
500
|
resolve();
|
|
510
501
|
})
|
|
511
502
|
.on('error', err => {
|
|
512
|
-
if (!timeout.aborted && !(
|
|
503
|
+
if (!timeout.aborted && !(core_1.Client.isErrorCode(err, 'ETIMEDOUT', 'ECONNRESET') && ++timeout.retries <= 10)) {
|
|
513
504
|
reject(err);
|
|
514
505
|
return;
|
|
515
506
|
}
|
|
516
507
|
resolve();
|
|
517
508
|
})
|
|
518
509
|
.on('timeout', () => {
|
|
519
|
-
if (!timeout.aborted && ++timeout.retries > 10
|
|
520
|
-
reject((0, types_1.errorMessage)(408
|
|
510
|
+
if (!timeout.aborted && ++timeout.retries > 10) {
|
|
511
|
+
reject((0, types_1.errorMessage)(408, 'HTTP request timeout'));
|
|
521
512
|
return;
|
|
522
513
|
}
|
|
523
514
|
resolve();
|
|
@@ -585,7 +576,7 @@ class Watch extends core_1.Client {
|
|
|
585
576
|
break;
|
|
586
577
|
}
|
|
587
578
|
catch (err) {
|
|
588
|
-
this.writeFail(["Unable to read file"
|
|
579
|
+
this.writeFail(["Unable to read file", path.basename(uri)], err, { type: 32, fatal: false });
|
|
589
580
|
}
|
|
590
581
|
}
|
|
591
582
|
}
|
|
@@ -601,9 +592,9 @@ class Watch extends core_1.Client {
|
|
|
601
592
|
DISK_MAP.set(uri, new Map([[dest, target]]));
|
|
602
593
|
}
|
|
603
594
|
else {
|
|
604
|
-
return 2
|
|
595
|
+
return 2;
|
|
605
596
|
}
|
|
606
|
-
return 0
|
|
597
|
+
return 0;
|
|
607
598
|
};
|
|
608
599
|
if ((0, types_1.isArray)(sourceFiles) && sourceFiles.some(file => this.canRead(file, { hostPermissionOnly: !!this.host }))) {
|
|
609
600
|
let index = 0;
|
|
@@ -625,33 +616,33 @@ class Watch extends core_1.Client {
|
|
|
625
616
|
if (status > 0) {
|
|
626
617
|
if (!message) {
|
|
627
618
|
switch (status) {
|
|
628
|
-
case 1
|
|
619
|
+
case 1:
|
|
629
620
|
if ((0, types_1.existsFlag)(item.flags)) {
|
|
630
621
|
continue;
|
|
631
622
|
}
|
|
632
623
|
message = 'ETag unavailable';
|
|
633
624
|
break;
|
|
634
|
-
case 2
|
|
625
|
+
case 2:
|
|
635
626
|
message = 'No read permission';
|
|
636
627
|
break;
|
|
637
|
-
case 3
|
|
628
|
+
case 3:
|
|
638
629
|
message = 'Server already in use';
|
|
639
630
|
break;
|
|
640
631
|
default:
|
|
641
|
-
message = "Unknown"
|
|
632
|
+
message = "Unknown";
|
|
642
633
|
break;
|
|
643
634
|
}
|
|
644
635
|
}
|
|
645
|
-
this.formatFail((16
|
|
636
|
+
this.formatFail((16 | (status === 2 ? 8192 : 0)), 'WATCH', ["Unable to watch file", watched && path.basename(watched)], (0, types_1.errorValue)(message, watched));
|
|
646
637
|
}
|
|
647
638
|
else {
|
|
648
|
-
this.formatMessage(16
|
|
639
|
+
this.formatMessage(16, 'WATCH', ['Start', interval + 'ms ' + (expires ? formatDate(expires) : 'never')], watched, { titleColor: 'blue' });
|
|
649
640
|
}
|
|
650
641
|
}
|
|
651
642
|
}
|
|
652
643
|
}
|
|
653
644
|
async modified(watch) {
|
|
654
|
-
this.formatMessage(16
|
|
645
|
+
this.formatMessage(16, 'WATCH', 'File modified', watch.uri, { ...core_1.Client.LOG_STYLE_WARN });
|
|
655
646
|
const { host, assets } = this;
|
|
656
647
|
let items, sanitize = false;
|
|
657
648
|
if (watch.main) {
|
|
@@ -681,7 +672,7 @@ class Watch extends core_1.Client {
|
|
|
681
672
|
}
|
|
682
673
|
}
|
|
683
674
|
if (!sanitize) {
|
|
684
|
-
items.forEach(item => item.flags |= 2
|
|
675
|
+
items.forEach(item => item.flags |= 2);
|
|
685
676
|
}
|
|
686
677
|
watch.captured = false;
|
|
687
678
|
try {
|
|
@@ -729,7 +720,7 @@ class Watch extends core_1.Client {
|
|
|
729
720
|
return await manager.start();
|
|
730
721
|
}
|
|
731
722
|
catch (err) {
|
|
732
|
-
this.writeFail(["Unknown"
|
|
723
|
+
this.writeFail(["Unknown", watch.url?.pathname || path.basename(watch.uri)], err);
|
|
733
724
|
}
|
|
734
725
|
}
|
|
735
726
|
configureServer({ ca, key, cert, passphrase, version, config }) {
|
|
@@ -788,7 +779,7 @@ class Watch extends core_1.Client {
|
|
|
788
779
|
return !!this[kTlsKey] && !!this[kTlsCert];
|
|
789
780
|
}
|
|
790
781
|
willAbort(value) {
|
|
791
|
-
return this.host ? this.host.willAbort(value) : value === "(watch)"
|
|
782
|
+
return this.host ? this.host.willAbort(value) : value === "(watch)";
|
|
792
783
|
}
|
|
793
784
|
set host(value) {
|
|
794
785
|
super.host = value;
|
|
@@ -836,7 +827,7 @@ class Watch extends core_1.Client {
|
|
|
836
827
|
}
|
|
837
828
|
}
|
|
838
829
|
_a = kInterval, _b = kPort, _c = kSecurePort, _d = kCa, _e = kTlsKey, _f = kTlsCert, _g = kTlsPassphrase, _h = kTlsVersion, _j = kTlsConfig;
|
|
839
|
-
Watch.PROCESS_TIMEOUT = 5 * 1000
|
|
830
|
+
Watch.PROCESS_TIMEOUT = 5 * 1000;
|
|
840
831
|
exports.default = Watch;
|
|
841
832
|
|
|
842
833
|
if (exports.default) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e-mc/watch",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.7",
|
|
4
4
|
"description": "Watch constructor for E-mc.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
"squared-functions"
|
|
18
18
|
],
|
|
19
19
|
"author": "An Pham <anpham6@gmail.com>",
|
|
20
|
-
"license": "
|
|
20
|
+
"license": "BSD 3-Clause",
|
|
21
21
|
"homepage": "https://github.com/anpham6/e-mc#readme",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@e-mc/core": "0.8.
|
|
24
|
-
"@e-mc/request": "0.8.
|
|
25
|
-
"@e-mc/types": "0.8.
|
|
23
|
+
"@e-mc/core": "0.8.7",
|
|
24
|
+
"@e-mc/request": "0.8.7",
|
|
25
|
+
"@e-mc/types": "0.8.7",
|
|
26
26
|
"picomatch": "^3.0.1",
|
|
27
27
|
"ws": "^8.16.0"
|
|
28
28
|
}
|