nlcurl 0.3.1 → 0.5.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 +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +84 -90
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/index.js +25 -25
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/output.d.ts +2 -2
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/cli/output.js +55 -55
- package/dist/cli/output.js.map +1 -1
- package/dist/cookies/jar.d.ts +1 -1
- package/dist/cookies/jar.d.ts.map +1 -1
- package/dist/cookies/jar.js +20 -22
- package/dist/cookies/jar.js.map +1 -1
- package/dist/cookies/parser.d.ts +1 -1
- package/dist/cookies/parser.d.ts.map +1 -1
- package/dist/cookies/parser.js +20 -22
- package/dist/cookies/parser.js.map +1 -1
- package/dist/core/client.d.ts +3 -3
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/client.js +9 -8
- package/dist/core/client.js.map +1 -1
- package/dist/core/errors.d.ts +64 -21
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +112 -36
- package/dist/core/errors.js.map +1 -1
- package/dist/core/request.d.ts +10 -5
- package/dist/core/request.d.ts.map +1 -1
- package/dist/core/response.d.ts +2 -2
- package/dist/core/response.d.ts.map +1 -1
- package/dist/core/response.js +6 -8
- package/dist/core/response.js.map +1 -1
- package/dist/core/session.d.ts +7 -6
- package/dist/core/session.d.ts.map +1 -1
- package/dist/core/session.js +58 -43
- package/dist/core/session.js.map +1 -1
- package/dist/core/validation.d.ts +96 -0
- package/dist/core/validation.d.ts.map +1 -0
- package/dist/core/validation.js +246 -0
- package/dist/core/validation.js.map +1 -0
- package/dist/fingerprints/akamai.d.ts +1 -1
- package/dist/fingerprints/akamai.d.ts.map +1 -1
- package/dist/fingerprints/akamai.js +3 -7
- package/dist/fingerprints/akamai.js.map +1 -1
- package/dist/fingerprints/database.d.ts +7 -7
- package/dist/fingerprints/database.d.ts.map +1 -1
- package/dist/fingerprints/database.js +12 -18
- package/dist/fingerprints/database.js.map +1 -1
- package/dist/fingerprints/extensions.d.ts.map +1 -1
- package/dist/fingerprints/extensions.js +4 -4
- package/dist/fingerprints/extensions.js.map +1 -1
- package/dist/fingerprints/ja3.d.ts +1 -1
- package/dist/fingerprints/ja3.d.ts.map +1 -1
- package/dist/fingerprints/ja3.js +12 -12
- package/dist/fingerprints/ja3.js.map +1 -1
- package/dist/fingerprints/profiles/chrome.d.ts +1 -1
- package/dist/fingerprints/profiles/chrome.d.ts.map +1 -1
- package/dist/fingerprints/profiles/chrome.js +59 -100
- package/dist/fingerprints/profiles/chrome.js.map +1 -1
- package/dist/fingerprints/profiles/edge.d.ts +1 -1
- package/dist/fingerprints/profiles/edge.d.ts.map +1 -1
- package/dist/fingerprints/profiles/edge.js +26 -26
- package/dist/fingerprints/profiles/edge.js.map +1 -1
- package/dist/fingerprints/profiles/firefox.d.ts +1 -1
- package/dist/fingerprints/profiles/firefox.d.ts.map +1 -1
- package/dist/fingerprints/profiles/firefox.js +35 -85
- package/dist/fingerprints/profiles/firefox.js.map +1 -1
- package/dist/fingerprints/profiles/safari.d.ts +1 -1
- package/dist/fingerprints/profiles/safari.d.ts.map +1 -1
- package/dist/fingerprints/profiles/safari.js +35 -68
- package/dist/fingerprints/profiles/safari.js.map +1 -1
- package/dist/fingerprints/profiles/tor.d.ts +1 -1
- package/dist/fingerprints/profiles/tor.d.ts.map +1 -1
- package/dist/fingerprints/profiles/tor.js +24 -57
- package/dist/fingerprints/profiles/tor.js.map +1 -1
- package/dist/fingerprints/types.d.ts +1 -1
- package/dist/fingerprints/types.d.ts.map +1 -1
- package/dist/http/h1/client.d.ts +4 -4
- package/dist/http/h1/client.d.ts.map +1 -1
- package/dist/http/h1/client.js +31 -31
- package/dist/http/h1/client.js.map +1 -1
- package/dist/http/h1/encoder.d.ts +1 -1
- package/dist/http/h1/encoder.d.ts.map +1 -1
- package/dist/http/h1/encoder.js +21 -20
- package/dist/http/h1/encoder.js.map +1 -1
- package/dist/http/h1/parser.d.ts +1 -1
- package/dist/http/h1/parser.d.ts.map +1 -1
- package/dist/http/h1/parser.js +29 -33
- package/dist/http/h1/parser.js.map +1 -1
- package/dist/http/h2/client.d.ts +5 -4
- package/dist/http/h2/client.d.ts.map +1 -1
- package/dist/http/h2/client.js +88 -76
- package/dist/http/h2/client.js.map +1 -1
- package/dist/http/h2/frames.d.ts +7 -3
- package/dist/http/h2/frames.d.ts.map +1 -1
- package/dist/http/h2/frames.js +16 -12
- package/dist/http/h2/frames.js.map +1 -1
- package/dist/http/h2/hpack.d.ts.map +1 -1
- package/dist/http/h2/hpack.js +331 -130
- package/dist/http/h2/hpack.js.map +1 -1
- package/dist/http/negotiator.d.ts +4 -4
- package/dist/http/negotiator.d.ts.map +1 -1
- package/dist/http/negotiator.js +45 -48
- package/dist/http/negotiator.js.map +1 -1
- package/dist/http/pool.d.ts +5 -5
- package/dist/http/pool.d.ts.map +1 -1
- package/dist/http/pool.js +5 -5
- package/dist/http/pool.js.map +1 -1
- package/dist/index.d.ts +16 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -9
- package/dist/index.js.map +1 -1
- package/dist/middleware/interceptor.d.ts +2 -2
- package/dist/middleware/interceptor.d.ts.map +1 -1
- package/dist/middleware/interceptor.js.map +1 -1
- package/dist/middleware/rate-limiter.d.ts.map +1 -1
- package/dist/middleware/rate-limiter.js +2 -0
- package/dist/middleware/rate-limiter.js.map +1 -1
- package/dist/middleware/retry.d.ts +6 -4
- package/dist/middleware/retry.d.ts.map +1 -1
- package/dist/middleware/retry.js +9 -7
- package/dist/middleware/retry.js.map +1 -1
- package/dist/proxy/http-proxy.d.ts +1 -1
- package/dist/proxy/http-proxy.d.ts.map +1 -1
- package/dist/proxy/http-proxy.js +14 -14
- package/dist/proxy/http-proxy.js.map +1 -1
- package/dist/proxy/socks.d.ts +1 -1
- package/dist/proxy/socks.d.ts.map +1 -1
- package/dist/proxy/socks.js +57 -28
- package/dist/proxy/socks.js.map +1 -1
- package/dist/tls/constants.d.ts.map +1 -1
- package/dist/tls/constants.js +1 -4
- package/dist/tls/constants.js.map +1 -1
- package/dist/tls/node-engine.d.ts +2 -2
- package/dist/tls/node-engine.d.ts.map +1 -1
- package/dist/tls/node-engine.js +58 -58
- package/dist/tls/node-engine.js.map +1 -1
- package/dist/tls/stealth/client-hello.d.ts +1 -1
- package/dist/tls/stealth/client-hello.d.ts.map +1 -1
- package/dist/tls/stealth/client-hello.js +8 -14
- package/dist/tls/stealth/client-hello.js.map +1 -1
- package/dist/tls/stealth/engine.d.ts +2 -2
- package/dist/tls/stealth/engine.d.ts.map +1 -1
- package/dist/tls/stealth/engine.js +23 -26
- package/dist/tls/stealth/engine.js.map +1 -1
- package/dist/tls/stealth/handshake.d.ts +3 -3
- package/dist/tls/stealth/handshake.d.ts.map +1 -1
- package/dist/tls/stealth/handshake.js +62 -74
- package/dist/tls/stealth/handshake.js.map +1 -1
- package/dist/tls/stealth/key-schedule.d.ts +2 -2
- package/dist/tls/stealth/key-schedule.d.ts.map +1 -1
- package/dist/tls/stealth/key-schedule.js +20 -20
- package/dist/tls/stealth/key-schedule.js.map +1 -1
- package/dist/tls/stealth/record-layer.d.ts +1 -1
- package/dist/tls/stealth/record-layer.d.ts.map +1 -1
- package/dist/tls/stealth/record-layer.js +13 -13
- package/dist/tls/stealth/record-layer.js.map +1 -1
- package/dist/tls/types.d.ts +4 -4
- package/dist/tls/types.d.ts.map +1 -1
- package/dist/utils/buffer-reader.d.ts.map +1 -1
- package/dist/utils/buffer-reader.js.map +1 -1
- package/dist/utils/buffer-writer.d.ts.map +1 -1
- package/dist/utils/buffer-writer.js +6 -0
- package/dist/utils/buffer-writer.js.map +1 -1
- package/dist/utils/encoding.d.ts +1 -1
- package/dist/utils/encoding.d.ts.map +1 -1
- package/dist/utils/encoding.js +23 -25
- package/dist/utils/encoding.js.map +1 -1
- package/dist/utils/happy-eyeballs.d.ts +26 -0
- package/dist/utils/happy-eyeballs.d.ts.map +1 -0
- package/dist/utils/happy-eyeballs.js +201 -0
- package/dist/utils/happy-eyeballs.js.map +1 -0
- package/dist/utils/logger.d.ts +48 -7
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +61 -13
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/url.d.ts.map +1 -1
- package/dist/utils/url.js +2 -2
- package/dist/utils/url.js.map +1 -1
- package/dist/ws/client.d.ts +2 -2
- package/dist/ws/client.d.ts.map +1 -1
- package/dist/ws/client.js +76 -71
- package/dist/ws/client.js.map +1 -1
- package/dist/ws/frame.d.ts.map +1 -1
- package/dist/ws/frame.js +8 -8
- package/dist/ws/frame.js.map +1 -1
- package/package.json +61 -57
package/dist/utils/logger.d.ts
CHANGED
|
@@ -4,33 +4,72 @@
|
|
|
4
4
|
*
|
|
5
5
|
* @typedef {'debug' | 'info' | 'warn' | 'error' | 'silent'} LogLevel
|
|
6
6
|
*/
|
|
7
|
-
export type LogLevel =
|
|
7
|
+
export type LogLevel = "debug" | "info" | "warn" | "error" | "silent";
|
|
8
|
+
/**
|
|
9
|
+
* Key-value metadata attached to every log entry produced by a child logger.
|
|
10
|
+
* Bindings are inherited from parent to child, allowing nested scoping.
|
|
11
|
+
*
|
|
12
|
+
* @typedef {Record<string, unknown>} LogBindings
|
|
13
|
+
*/
|
|
14
|
+
export type LogBindings = Record<string, unknown>;
|
|
8
15
|
/**
|
|
9
16
|
* Minimal logger interface consumed throughout the library. Implementations
|
|
10
17
|
* must provide four severity methods; all parameters follow `console.log`
|
|
11
18
|
* semantics (a primary message string followed by optional extra values).
|
|
12
19
|
*/
|
|
13
20
|
export interface Logger {
|
|
21
|
+
/** Emits a diagnostic message useful only during development. */
|
|
14
22
|
debug(message: string, ...args: unknown[]): void;
|
|
23
|
+
/** Emits a significant lifecycle or business event. */
|
|
15
24
|
info(message: string, ...args: unknown[]): void;
|
|
25
|
+
/** Emits a warning about an unexpected but recoverable condition. */
|
|
16
26
|
warn(message: string, ...args: unknown[]): void;
|
|
27
|
+
/** Emits an error indicating an operation failure that requires attention. */
|
|
17
28
|
error(message: string, ...args: unknown[]): void;
|
|
18
29
|
}
|
|
19
30
|
/**
|
|
20
31
|
* Default {@link Logger} implementation that writes to `process.stderr`.
|
|
21
32
|
* Messages are prefixed with `[nlcurl:<level>]` and only emitted when the
|
|
22
33
|
* message severity meets or exceeds the configured `level`.
|
|
34
|
+
*
|
|
35
|
+
* Supports scoped child loggers via {@link ConsoleLogger.child}, which
|
|
36
|
+
* prepend a component tag to every message for easy filtering.
|
|
23
37
|
*/
|
|
24
38
|
export declare class ConsoleLogger implements Logger {
|
|
25
39
|
private level;
|
|
40
|
+
private readonly prefix;
|
|
41
|
+
private readonly bindings;
|
|
26
42
|
/**
|
|
27
43
|
* Creates a new ConsoleLogger.
|
|
28
44
|
*
|
|
29
|
-
* @param {LogLevel}
|
|
45
|
+
* @param {LogLevel} [level='warn'] - Minimum severity level to emit.
|
|
46
|
+
* @param {string} [prefix=''] - Component prefix prepended to every message.
|
|
47
|
+
* @param {LogBindings} [bindings={}] - Key-value metadata appended to every message.
|
|
48
|
+
*/
|
|
49
|
+
constructor(level?: LogLevel, prefix?: string, bindings?: LogBindings);
|
|
50
|
+
/**
|
|
51
|
+
* Creates a child logger that inherits this logger's level and prepends
|
|
52
|
+
* an additional component tag to every message. Bindings from the parent
|
|
53
|
+
* are merged with the child's bindings (child values win on conflict).
|
|
54
|
+
*
|
|
55
|
+
* @param {LogBindings} bindings - Additional metadata for the child scope.
|
|
56
|
+
* @returns {ConsoleLogger} A new scoped logger instance.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* const logger = new ConsoleLogger('debug');
|
|
60
|
+
* const child = logger.child({ component: 'h2' });
|
|
61
|
+
* child.debug('stream opened', { streamId: 1 });
|
|
62
|
+
*/
|
|
63
|
+
child(bindings: LogBindings): ConsoleLogger;
|
|
64
|
+
/**
|
|
65
|
+
* Updates the minimum severity level at runtime without creating a new
|
|
66
|
+
* logger instance.
|
|
67
|
+
*
|
|
68
|
+
* @param {LogLevel} level - New minimum severity level.
|
|
30
69
|
*/
|
|
31
|
-
|
|
70
|
+
setLevel(level: LogLevel): void;
|
|
32
71
|
/**
|
|
33
|
-
* Emits a debug-level message to `stderr`
|
|
72
|
+
* Emits a debug-level message to `stderr` -- only written when the
|
|
34
73
|
* configured minimum level is `'debug'`.
|
|
35
74
|
*
|
|
36
75
|
* @param {string} message - Primary log message.
|
|
@@ -38,7 +77,7 @@ export declare class ConsoleLogger implements Logger {
|
|
|
38
77
|
*/
|
|
39
78
|
debug(message: string, ...args: unknown[]): void;
|
|
40
79
|
/**
|
|
41
|
-
* Emits an info-level message to `stderr`
|
|
80
|
+
* Emits an info-level message to `stderr` -- only written when the
|
|
42
81
|
* configured minimum level is `'debug'` or `'info'`.
|
|
43
82
|
*
|
|
44
83
|
* @param {string} message - Primary log message.
|
|
@@ -46,7 +85,7 @@ export declare class ConsoleLogger implements Logger {
|
|
|
46
85
|
*/
|
|
47
86
|
info(message: string, ...args: unknown[]): void;
|
|
48
87
|
/**
|
|
49
|
-
* Emits a warn-level message to `stderr`
|
|
88
|
+
* Emits a warn-level message to `stderr` -- only written when the
|
|
50
89
|
* configured minimum level is `'debug'`, `'info'`, or `'warn'`.
|
|
51
90
|
*
|
|
52
91
|
* @param {string} message - Primary log message.
|
|
@@ -54,14 +93,16 @@ export declare class ConsoleLogger implements Logger {
|
|
|
54
93
|
*/
|
|
55
94
|
warn(message: string, ...args: unknown[]): void;
|
|
56
95
|
/**
|
|
57
|
-
* Emits an error-level message to `stderr`
|
|
96
|
+
* Emits an error-level message to `stderr` -- only written when the
|
|
58
97
|
* configured minimum level is not `'silent'`.
|
|
59
98
|
*
|
|
60
99
|
* @param {string} message - Primary log message.
|
|
61
100
|
* @param {...unknown} args - Additional values appended after the message.
|
|
62
101
|
*/
|
|
63
102
|
error(message: string, ...args: unknown[]): void;
|
|
103
|
+
private write;
|
|
64
104
|
private formatArgs;
|
|
105
|
+
private resolveLevel;
|
|
65
106
|
}
|
|
66
107
|
/**
|
|
67
108
|
* A no-op {@link Logger} that discards all messages. Assign this via
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEtE;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAUlD;;;;GAIG;AACH,MAAM,WAAW,MAAM;IACrB,iEAAiE;IACjE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACjD,uDAAuD;IACvD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChD,qEAAqE;IACrE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChD,8EAA8E;IAC9E,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CAClD;AAED;;;;;;;GAOG;AACH,qBAAa,aAAc,YAAW,MAAM;IAC1C,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAc;IAEvC;;;;;;OAMG;gBACS,KAAK,GAAE,QAAiB,EAAE,MAAM,GAAE,MAAW,EAAE,QAAQ,GAAE,WAAgB;IAMrF;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,QAAQ,EAAE,WAAW,GAAG,aAAa;IAO3C;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAI/B;;;;;;OAMG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAMhD;;;;;;OAMG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAM/C;;;;;;OAMG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAM/C;;;;;;OAMG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAMhD,OAAO,CAAC,KAAK;IAKb,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,YAAY;CAMrB;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,MAK3B,CAAC;AAIF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAErD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC"}
|
package/dist/utils/logger.js
CHANGED
|
@@ -9,19 +9,56 @@ const LEVEL_ORDER = {
|
|
|
9
9
|
* Default {@link Logger} implementation that writes to `process.stderr`.
|
|
10
10
|
* Messages are prefixed with `[nlcurl:<level>]` and only emitted when the
|
|
11
11
|
* message severity meets or exceeds the configured `level`.
|
|
12
|
+
*
|
|
13
|
+
* Supports scoped child loggers via {@link ConsoleLogger.child}, which
|
|
14
|
+
* prepend a component tag to every message for easy filtering.
|
|
12
15
|
*/
|
|
13
16
|
export class ConsoleLogger {
|
|
14
17
|
level;
|
|
18
|
+
prefix;
|
|
19
|
+
bindings;
|
|
15
20
|
/**
|
|
16
21
|
* Creates a new ConsoleLogger.
|
|
17
22
|
*
|
|
18
|
-
* @param {LogLevel}
|
|
23
|
+
* @param {LogLevel} [level='warn'] - Minimum severity level to emit.
|
|
24
|
+
* @param {string} [prefix=''] - Component prefix prepended to every message.
|
|
25
|
+
* @param {LogBindings} [bindings={}] - Key-value metadata appended to every message.
|
|
26
|
+
*/
|
|
27
|
+
constructor(level = "warn", prefix = "", bindings = {}) {
|
|
28
|
+
this.level = LEVEL_ORDER[level];
|
|
29
|
+
this.prefix = prefix;
|
|
30
|
+
this.bindings = bindings;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Creates a child logger that inherits this logger's level and prepends
|
|
34
|
+
* an additional component tag to every message. Bindings from the parent
|
|
35
|
+
* are merged with the child's bindings (child values win on conflict).
|
|
36
|
+
*
|
|
37
|
+
* @param {LogBindings} bindings - Additional metadata for the child scope.
|
|
38
|
+
* @returns {ConsoleLogger} A new scoped logger instance.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* const logger = new ConsoleLogger('debug');
|
|
42
|
+
* const child = logger.child({ component: 'h2' });
|
|
43
|
+
* child.debug('stream opened', { streamId: 1 });
|
|
19
44
|
*/
|
|
20
|
-
|
|
45
|
+
child(bindings) {
|
|
46
|
+
const component = typeof bindings["component"] === "string" ? bindings["component"] : "";
|
|
47
|
+
const childPrefix = this.prefix ? (component ? `${this.prefix}:${component}` : this.prefix) : component;
|
|
48
|
+
const merged = { ...this.bindings, ...bindings };
|
|
49
|
+
return new ConsoleLogger(this.resolveLevel(), childPrefix, merged);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Updates the minimum severity level at runtime without creating a new
|
|
53
|
+
* logger instance.
|
|
54
|
+
*
|
|
55
|
+
* @param {LogLevel} level - New minimum severity level.
|
|
56
|
+
*/
|
|
57
|
+
setLevel(level) {
|
|
21
58
|
this.level = LEVEL_ORDER[level];
|
|
22
59
|
}
|
|
23
60
|
/**
|
|
24
|
-
* Emits a debug-level message to `stderr`
|
|
61
|
+
* Emits a debug-level message to `stderr` -- only written when the
|
|
25
62
|
* configured minimum level is `'debug'`.
|
|
26
63
|
*
|
|
27
64
|
* @param {string} message - Primary log message.
|
|
@@ -29,11 +66,11 @@ export class ConsoleLogger {
|
|
|
29
66
|
*/
|
|
30
67
|
debug(message, ...args) {
|
|
31
68
|
if (this.level <= LEVEL_ORDER.debug) {
|
|
32
|
-
|
|
69
|
+
this.write("debug", message, args);
|
|
33
70
|
}
|
|
34
71
|
}
|
|
35
72
|
/**
|
|
36
|
-
* Emits an info-level message to `stderr`
|
|
73
|
+
* Emits an info-level message to `stderr` -- only written when the
|
|
37
74
|
* configured minimum level is `'debug'` or `'info'`.
|
|
38
75
|
*
|
|
39
76
|
* @param {string} message - Primary log message.
|
|
@@ -41,11 +78,11 @@ export class ConsoleLogger {
|
|
|
41
78
|
*/
|
|
42
79
|
info(message, ...args) {
|
|
43
80
|
if (this.level <= LEVEL_ORDER.info) {
|
|
44
|
-
|
|
81
|
+
this.write("info", message, args);
|
|
45
82
|
}
|
|
46
83
|
}
|
|
47
84
|
/**
|
|
48
|
-
* Emits a warn-level message to `stderr`
|
|
85
|
+
* Emits a warn-level message to `stderr` -- only written when the
|
|
49
86
|
* configured minimum level is `'debug'`, `'info'`, or `'warn'`.
|
|
50
87
|
*
|
|
51
88
|
* @param {string} message - Primary log message.
|
|
@@ -53,11 +90,11 @@ export class ConsoleLogger {
|
|
|
53
90
|
*/
|
|
54
91
|
warn(message, ...args) {
|
|
55
92
|
if (this.level <= LEVEL_ORDER.warn) {
|
|
56
|
-
|
|
93
|
+
this.write("warn", message, args);
|
|
57
94
|
}
|
|
58
95
|
}
|
|
59
96
|
/**
|
|
60
|
-
* Emits an error-level message to `stderr`
|
|
97
|
+
* Emits an error-level message to `stderr` -- only written when the
|
|
61
98
|
* configured minimum level is not `'silent'`.
|
|
62
99
|
*
|
|
63
100
|
* @param {string} message - Primary log message.
|
|
@@ -65,13 +102,24 @@ export class ConsoleLogger {
|
|
|
65
102
|
*/
|
|
66
103
|
error(message, ...args) {
|
|
67
104
|
if (this.level <= LEVEL_ORDER.error) {
|
|
68
|
-
|
|
105
|
+
this.write("error", message, args);
|
|
69
106
|
}
|
|
70
107
|
}
|
|
108
|
+
write(level, message, args) {
|
|
109
|
+
const tag = this.prefix ? `nlcurl:${this.prefix}:${level}` : `nlcurl:${level}`;
|
|
110
|
+
process.stderr.write(`[${tag}] ${message}${this.formatArgs(args)}\n`);
|
|
111
|
+
}
|
|
71
112
|
formatArgs(args) {
|
|
72
113
|
if (args.length === 0)
|
|
73
|
-
return
|
|
74
|
-
return
|
|
114
|
+
return "";
|
|
115
|
+
return " " + args.map((a) => (typeof a === "string" ? a : JSON.stringify(a))).join(" ");
|
|
116
|
+
}
|
|
117
|
+
resolveLevel() {
|
|
118
|
+
for (const [name, order] of Object.entries(LEVEL_ORDER)) {
|
|
119
|
+
if (order === this.level)
|
|
120
|
+
return name;
|
|
121
|
+
}
|
|
122
|
+
return "warn";
|
|
75
123
|
}
|
|
76
124
|
}
|
|
77
125
|
/**
|
|
@@ -84,7 +132,7 @@ export const SILENT_LOGGER = {
|
|
|
84
132
|
warn() { },
|
|
85
133
|
error() { },
|
|
86
134
|
};
|
|
87
|
-
let _default = new ConsoleLogger(
|
|
135
|
+
let _default = new ConsoleLogger("warn");
|
|
88
136
|
/**
|
|
89
137
|
* Replaces the process-wide default logger used by all NLcURL internals.
|
|
90
138
|
*
|
package/dist/utils/logger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/url.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../src/utils/url.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../src/utils/url.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO7E;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,MAAM,CASpG;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAEzC;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI5C;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAOpE;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG/C"}
|
package/dist/utils/url.js
CHANGED
|
@@ -55,7 +55,7 @@ export function parseURL(raw) {
|
|
|
55
55
|
*/
|
|
56
56
|
export function originOf(url) {
|
|
57
57
|
const u = new URL(url);
|
|
58
|
-
const port = u.port || (u.protocol ===
|
|
58
|
+
const port = u.port || (u.protocol === "https:" ? "443" : "80");
|
|
59
59
|
return `${u.protocol}//${u.hostname}:${port}`;
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
@@ -76,7 +76,7 @@ export function sniHost(url) {
|
|
|
76
76
|
*/
|
|
77
77
|
export function hostPort(url) {
|
|
78
78
|
const u = new URL(url);
|
|
79
|
-
const defaultPort = u.protocol ===
|
|
79
|
+
const defaultPort = u.protocol === "https:" ? 443 : 80;
|
|
80
80
|
return {
|
|
81
81
|
host: u.hostname,
|
|
82
82
|
port: u.port ? parseInt(u.port, 10) : defaultPort,
|
package/dist/utils/url.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url.js","sourceRoot":"","sources":["../../src/utils/url.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"url.js","sourceRoot":"","sources":["../../src/utils/url.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,IAAwB,EAAE,QAAgB;IACnE,IAAI,CAAC,IAAI;QAAE,OAAO,QAAQ,CAAC;IAC3B,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,MAAkD;IAC1F,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IAE5D,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;YAAE,SAAS;QACpD,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC3B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;AACtB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACvB,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAChE,OAAO,GAAG,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC;AAChD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;AAC/B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACvB,MAAM,WAAW,GAAG,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACvD,OAAO;QACL,IAAI,EAAE,CAAC,CAAC,QAAQ;QAChB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW;KAClD,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACvB,OAAO,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC;AAC/B,CAAC"}
|
package/dist/ws/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EventEmitter } from
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
2
|
/**
|
|
3
3
|
* Options for creating a {@link WebSocketClient} connection.
|
|
4
4
|
*
|
|
@@ -23,7 +23,7 @@ export interface WebSocketOptions {
|
|
|
23
23
|
*
|
|
24
24
|
* @typedef {'connecting' | 'open' | 'closing' | 'closed'} WebSocketState
|
|
25
25
|
*/
|
|
26
|
-
export type WebSocketState =
|
|
26
|
+
export type WebSocketState = "connecting" | "open" | "closing" | "closed";
|
|
27
27
|
/**
|
|
28
28
|
* Typed event map for {@link WebSocketClient}.
|
|
29
29
|
*
|
package/dist/ws/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/ws/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/ws/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAW3C;;;;;;;;;;GAUG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE1E;;;;;;;;;;GAUG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,EAAE,CAAC;IACT,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACpD,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACtB,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACrB,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;CACtB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,eAAgB,SAAQ,YAAY;IACxC,KAAK,EAAE,cAAc,CAAgB;IACrC,QAAQ,SAAM;IACrB,SAAgB,GAAG,EAAE,MAAM,CAAC;IAE5B,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,cAAc,CAAuB;IAE7C;;;;;OAKG;gBACS,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB;IAWvD;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAM5B;;;;;OAKG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK9B;;;;;OAKG;IACH,IAAI,CAAC,IAAI,GAAE,MAAwB,GAAG,IAAI;IAK1C;;;;;;OAMG;IACH,KAAK,CAAC,IAAI,SAAO,EAAE,MAAM,SAAK,GAAG,IAAI;IAYrC,OAAO,CAAC,UAAU;YAMJ,OAAO;IA4DrB,OAAO,CAAC,cAAc;IAqGtB,OAAO,CAAC,MAAM;IAKd,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,WAAW;CAwDpB"}
|
package/dist/ws/client.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { EventEmitter } from
|
|
2
|
-
import { NodeTLSEngine } from
|
|
3
|
-
import { StealthTLSEngine } from
|
|
4
|
-
import { getProfile } from
|
|
5
|
-
import { NLcURLError, ConnectionError } from
|
|
6
|
-
import {
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import { NodeTLSEngine } from "../tls/node-engine.js";
|
|
3
|
+
import { StealthTLSEngine } from "../tls/stealth/engine.js";
|
|
4
|
+
import { getProfile } from "../fingerprints/database.js";
|
|
5
|
+
import { NLcURLError, ConnectionError } from "../core/errors.js";
|
|
6
|
+
import { validateWebSocketUrl } from "../core/validation.js";
|
|
7
|
+
import { encodeFrame, FrameParser, Opcode, generateWebSocketKey, computeAcceptKey } from "./frame.js";
|
|
7
8
|
/**
|
|
8
9
|
* WebSocket client with optional browser fingerprint impersonation. Emits
|
|
9
10
|
* typed lifecycle events (`open`, `message`, `close`, `error`, `ping`, `pong`).
|
|
@@ -16,8 +17,8 @@ import { encodeFrame, FrameParser, Opcode, generateWebSocketKey, computeAcceptKe
|
|
|
16
17
|
* ws.on('message', (data) => console.log(data));
|
|
17
18
|
*/
|
|
18
19
|
export class WebSocketClient extends EventEmitter {
|
|
19
|
-
state =
|
|
20
|
-
protocol =
|
|
20
|
+
state = "connecting";
|
|
21
|
+
protocol = "";
|
|
21
22
|
url;
|
|
22
23
|
socket = null;
|
|
23
24
|
parser = new FrameParser();
|
|
@@ -31,10 +32,11 @@ export class WebSocketClient extends EventEmitter {
|
|
|
31
32
|
*/
|
|
32
33
|
constructor(url, options = {}) {
|
|
33
34
|
super();
|
|
35
|
+
validateWebSocketUrl(url);
|
|
34
36
|
this.url = url;
|
|
35
37
|
this.connect(url, options).catch((err) => {
|
|
36
|
-
this.state =
|
|
37
|
-
this.emit(
|
|
38
|
+
this.state = "closed";
|
|
39
|
+
this.emit("error", err);
|
|
38
40
|
});
|
|
39
41
|
}
|
|
40
42
|
/**
|
|
@@ -45,7 +47,7 @@ export class WebSocketClient extends EventEmitter {
|
|
|
45
47
|
*/
|
|
46
48
|
sendText(data) {
|
|
47
49
|
this.assertOpen();
|
|
48
|
-
const payload = Buffer.from(data,
|
|
50
|
+
const payload = Buffer.from(data, "utf8");
|
|
49
51
|
this.socket.write(encodeFrame(Opcode.TEXT, payload));
|
|
50
52
|
}
|
|
51
53
|
/**
|
|
@@ -75,73 +77,67 @@ export class WebSocketClient extends EventEmitter {
|
|
|
75
77
|
* @param {number} [code=1000] - WebSocket close status code.
|
|
76
78
|
* @param {string} [reason=''] - Human-readable close reason (UTF-8, max 123 bytes).
|
|
77
79
|
*/
|
|
78
|
-
close(code = 1000, reason =
|
|
79
|
-
if (this.state !==
|
|
80
|
+
close(code = 1000, reason = "") {
|
|
81
|
+
if (this.state !== "open")
|
|
80
82
|
return;
|
|
81
|
-
this.state =
|
|
82
|
-
const reasonBuf = Buffer.from(reason,
|
|
83
|
+
this.state = "closing";
|
|
84
|
+
const reasonBuf = Buffer.from(reason, "utf8");
|
|
83
85
|
const payload = Buffer.allocUnsafe(2 + reasonBuf.length);
|
|
84
86
|
payload.writeUInt16BE(code, 0);
|
|
85
87
|
reasonBuf.copy(payload, 2);
|
|
86
88
|
this.socket.write(encodeFrame(Opcode.CLOSE, payload));
|
|
87
89
|
}
|
|
88
90
|
assertOpen() {
|
|
89
|
-
if (this.state !==
|
|
90
|
-
throw new NLcURLError(
|
|
91
|
+
if (this.state !== "open") {
|
|
92
|
+
throw new NLcURLError("WebSocket is not open", "ERR_WS_NOT_OPEN");
|
|
91
93
|
}
|
|
92
94
|
}
|
|
93
95
|
async connect(url, options) {
|
|
94
96
|
const parsed = new URL(url);
|
|
95
|
-
const isSecure = parsed.protocol ===
|
|
96
|
-
const port = parsed.port
|
|
97
|
-
? parseInt(parsed.port, 10)
|
|
98
|
-
: isSecure ? 443 : 80;
|
|
97
|
+
const isSecure = parsed.protocol === "wss:";
|
|
98
|
+
const port = parsed.port ? parseInt(parsed.port, 10) : isSecure ? 443 : 80;
|
|
99
99
|
const host = parsed.hostname;
|
|
100
|
-
const profile = options.impersonate
|
|
101
|
-
? getProfile(options.impersonate) ?? undefined
|
|
102
|
-
: undefined;
|
|
100
|
+
const profile = options.impersonate ? (getProfile(options.impersonate) ?? undefined) : undefined;
|
|
103
101
|
let transport;
|
|
104
102
|
if (isSecure) {
|
|
105
|
-
const engine = options.stealth
|
|
106
|
-
? new StealthTLSEngine()
|
|
107
|
-
: new NodeTLSEngine();
|
|
103
|
+
const engine = options.stealth ? new StealthTLSEngine() : new NodeTLSEngine();
|
|
108
104
|
const tlsOpts = {
|
|
109
105
|
host,
|
|
110
106
|
port,
|
|
111
107
|
servername: host,
|
|
112
108
|
insecure: options.insecure ?? false,
|
|
113
|
-
alpnProtocols: [
|
|
109
|
+
alpnProtocols: ["http/1.1"],
|
|
114
110
|
timeout: options.timeout,
|
|
115
111
|
};
|
|
116
112
|
const tlsSocket = await engine.connect(tlsOpts, profile);
|
|
117
113
|
transport = tlsSocket;
|
|
118
114
|
}
|
|
119
115
|
else {
|
|
120
|
-
const net = await import(
|
|
116
|
+
const net = await import("node:net");
|
|
121
117
|
transport = await new Promise((resolve, reject) => {
|
|
122
118
|
const sock = net.createConnection({ host, port }, () => resolve(sock));
|
|
123
|
-
sock.once(
|
|
119
|
+
sock.once("error", reject);
|
|
124
120
|
if (options.timeout) {
|
|
125
121
|
sock.setTimeout(options.timeout, () => {
|
|
126
122
|
sock.destroy();
|
|
127
|
-
reject(new ConnectionError(
|
|
123
|
+
reject(new ConnectionError("WebSocket connection timed out"));
|
|
128
124
|
});
|
|
129
125
|
}
|
|
130
126
|
});
|
|
131
127
|
}
|
|
132
128
|
this.socket = transport;
|
|
133
129
|
await this.performUpgrade(transport, parsed, options);
|
|
134
|
-
this.state =
|
|
135
|
-
this.emit(
|
|
136
|
-
transport.on(
|
|
137
|
-
transport.on(
|
|
138
|
-
this.state =
|
|
139
|
-
this.emit(
|
|
130
|
+
this.state = "open";
|
|
131
|
+
this.emit("open");
|
|
132
|
+
transport.on("data", (chunk) => this.onData(chunk));
|
|
133
|
+
transport.on("error", (err) => {
|
|
134
|
+
this.state = "closed";
|
|
135
|
+
this.emit("error", err);
|
|
140
136
|
});
|
|
141
|
-
transport.on(
|
|
142
|
-
if (this.state !==
|
|
143
|
-
this.state =
|
|
144
|
-
this.emit(
|
|
137
|
+
transport.on("close", () => {
|
|
138
|
+
if (this.state !== "closed") {
|
|
139
|
+
this.state = "closed";
|
|
140
|
+
this.emit("close", 1006, "Connection lost");
|
|
145
141
|
}
|
|
146
142
|
});
|
|
147
143
|
this.drainBufferedFrames();
|
|
@@ -149,7 +145,7 @@ export class WebSocketClient extends EventEmitter {
|
|
|
149
145
|
performUpgrade(socket, url, options) {
|
|
150
146
|
return new Promise((resolve, reject) => {
|
|
151
147
|
const key = generateWebSocketKey();
|
|
152
|
-
const path = (url.pathname ||
|
|
148
|
+
const path = (url.pathname || "/") + (url.search || "");
|
|
153
149
|
let request = `GET ${path} HTTP/1.1\r\n`;
|
|
154
150
|
request += `Host: ${url.host}\r\n`;
|
|
155
151
|
request += `Upgrade: websocket\r\n`;
|
|
@@ -157,7 +153,7 @@ export class WebSocketClient extends EventEmitter {
|
|
|
157
153
|
request += `Sec-WebSocket-Key: ${key}\r\n`;
|
|
158
154
|
request += `Sec-WebSocket-Version: 13\r\n`;
|
|
159
155
|
if (options.protocols && options.protocols.length > 0) {
|
|
160
|
-
request += `Sec-WebSocket-Protocol: ${options.protocols.join(
|
|
156
|
+
request += `Sec-WebSocket-Protocol: ${options.protocols.join(", ")}\r\n`;
|
|
161
157
|
}
|
|
162
158
|
if (options.headers) {
|
|
163
159
|
for (const [k, v] of Object.entries(options.headers)) {
|
|
@@ -168,39 +164,46 @@ export class WebSocketClient extends EventEmitter {
|
|
|
168
164
|
socket.write(request);
|
|
169
165
|
let responseData = Buffer.alloc(0);
|
|
170
166
|
const expectedAccept = computeAcceptKey(key);
|
|
167
|
+
let upgradeTimer;
|
|
168
|
+
if (options.timeout && options.timeout > 0) {
|
|
169
|
+
upgradeTimer = setTimeout(() => {
|
|
170
|
+
cleanup();
|
|
171
|
+
reject(new NLcURLError("WebSocket upgrade timed out", "ERR_WS_TIMEOUT"));
|
|
172
|
+
}, options.timeout);
|
|
173
|
+
}
|
|
171
174
|
const onData = (chunk) => {
|
|
172
175
|
responseData = Buffer.concat([responseData, chunk]);
|
|
173
|
-
const text = responseData.toString(
|
|
174
|
-
const headerEnd = text.indexOf(
|
|
176
|
+
const text = responseData.toString("utf8");
|
|
177
|
+
const headerEnd = text.indexOf("\r\n\r\n");
|
|
175
178
|
if (headerEnd === -1) {
|
|
176
179
|
if (responseData.length > 16384) {
|
|
177
180
|
cleanup();
|
|
178
|
-
reject(new NLcURLError(
|
|
181
|
+
reject(new NLcURLError("WebSocket upgrade response too large", "ERR_WS_UPGRADE"));
|
|
179
182
|
}
|
|
180
183
|
return;
|
|
181
184
|
}
|
|
182
185
|
cleanup();
|
|
183
186
|
const headerStr = text.substring(0, headerEnd);
|
|
184
|
-
const [statusLine, ...headerLines] = headerStr.split(
|
|
187
|
+
const [statusLine, ...headerLines] = headerStr.split("\r\n");
|
|
185
188
|
if (!statusLine) {
|
|
186
|
-
return reject(new NLcURLError(
|
|
189
|
+
return reject(new NLcURLError("Empty upgrade response", "ERR_WS_UPGRADE"));
|
|
187
190
|
}
|
|
188
191
|
const statusMatch = statusLine.match(/^HTTP\/\d\.\d (\d{3})/);
|
|
189
|
-
if (!statusMatch || statusMatch[1] !==
|
|
190
|
-
return reject(new NLcURLError(`WebSocket upgrade failed: ${statusLine}`,
|
|
192
|
+
if (!statusMatch || statusMatch[1] !== "101") {
|
|
193
|
+
return reject(new NLcURLError(`WebSocket upgrade failed: ${statusLine}`, "ERR_WS_UPGRADE"));
|
|
191
194
|
}
|
|
192
195
|
const headers = new Map();
|
|
193
196
|
for (const line of headerLines) {
|
|
194
|
-
const colonIdx = line.indexOf(
|
|
197
|
+
const colonIdx = line.indexOf(":");
|
|
195
198
|
if (colonIdx > 0) {
|
|
196
199
|
headers.set(line.substring(0, colonIdx).trim().toLowerCase(), line.substring(colonIdx + 1).trim());
|
|
197
200
|
}
|
|
198
201
|
}
|
|
199
|
-
const accept = headers.get(
|
|
202
|
+
const accept = headers.get("sec-websocket-accept");
|
|
200
203
|
if (accept !== expectedAccept) {
|
|
201
|
-
return reject(new NLcURLError(
|
|
204
|
+
return reject(new NLcURLError("Invalid Sec-WebSocket-Accept header", "ERR_WS_UPGRADE"));
|
|
202
205
|
}
|
|
203
|
-
this.protocol = headers.get(
|
|
206
|
+
this.protocol = headers.get("sec-websocket-protocol") ?? "";
|
|
204
207
|
const remaining = responseData.subarray(headerEnd + 4);
|
|
205
208
|
if (remaining.length > 0) {
|
|
206
209
|
this.parser.push(remaining);
|
|
@@ -212,11 +215,13 @@ export class WebSocketClient extends EventEmitter {
|
|
|
212
215
|
reject(err);
|
|
213
216
|
};
|
|
214
217
|
const cleanup = () => {
|
|
215
|
-
|
|
216
|
-
|
|
218
|
+
if (upgradeTimer)
|
|
219
|
+
clearTimeout(upgradeTimer);
|
|
220
|
+
socket.removeListener("data", onData);
|
|
221
|
+
socket.removeListener("error", onError);
|
|
217
222
|
};
|
|
218
|
-
socket.on(
|
|
219
|
-
socket.on(
|
|
223
|
+
socket.on("data", onData);
|
|
224
|
+
socket.on("error", onError);
|
|
220
225
|
});
|
|
221
226
|
}
|
|
222
227
|
onData(chunk) {
|
|
@@ -235,8 +240,8 @@ export class WebSocketClient extends EventEmitter {
|
|
|
235
240
|
case Opcode.BINARY:
|
|
236
241
|
if (frame.fin) {
|
|
237
242
|
const isBinary = frame.opcode === Opcode.BINARY;
|
|
238
|
-
const data = isBinary ? frame.payload : frame.payload.toString(
|
|
239
|
-
this.emit(
|
|
243
|
+
const data = isBinary ? frame.payload : frame.payload.toString("utf8");
|
|
244
|
+
this.emit("message", data, isBinary);
|
|
240
245
|
}
|
|
241
246
|
else {
|
|
242
247
|
this.fragmentOpcode = frame.opcode;
|
|
@@ -249,34 +254,34 @@ export class WebSocketClient extends EventEmitter {
|
|
|
249
254
|
const assembled = Buffer.concat(this.fragments);
|
|
250
255
|
this.fragments = [];
|
|
251
256
|
const isBinary = this.fragmentOpcode === Opcode.BINARY;
|
|
252
|
-
const data = isBinary ? assembled : assembled.toString(
|
|
253
|
-
this.emit(
|
|
257
|
+
const data = isBinary ? assembled : assembled.toString("utf8");
|
|
258
|
+
this.emit("message", data, isBinary);
|
|
254
259
|
}
|
|
255
260
|
break;
|
|
256
261
|
case Opcode.CLOSE: {
|
|
257
262
|
let code = 1005;
|
|
258
|
-
let reason =
|
|
263
|
+
let reason = "";
|
|
259
264
|
if (frame.payload.length >= 2) {
|
|
260
265
|
code = frame.payload.readUInt16BE(0);
|
|
261
|
-
reason = frame.payload.subarray(2).toString(
|
|
266
|
+
reason = frame.payload.subarray(2).toString("utf8");
|
|
262
267
|
}
|
|
263
|
-
if (this.state ===
|
|
264
|
-
this.state =
|
|
268
|
+
if (this.state === "open") {
|
|
269
|
+
this.state = "closing";
|
|
265
270
|
this.socket.write(encodeFrame(Opcode.CLOSE, frame.payload));
|
|
266
271
|
}
|
|
267
|
-
this.state =
|
|
272
|
+
this.state = "closed";
|
|
268
273
|
this.socket?.destroy();
|
|
269
|
-
this.emit(
|
|
274
|
+
this.emit("close", code, reason);
|
|
270
275
|
break;
|
|
271
276
|
}
|
|
272
277
|
case Opcode.PING:
|
|
273
|
-
this.emit(
|
|
274
|
-
if (this.state ===
|
|
278
|
+
this.emit("ping", frame.payload);
|
|
279
|
+
if (this.state === "open") {
|
|
275
280
|
this.socket.write(encodeFrame(Opcode.PONG, frame.payload));
|
|
276
281
|
}
|
|
277
282
|
break;
|
|
278
283
|
case Opcode.PONG:
|
|
279
|
-
this.emit(
|
|
284
|
+
this.emit("pong", frame.payload);
|
|
280
285
|
break;
|
|
281
286
|
}
|
|
282
287
|
}
|