nlcurl 0.1.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/LICENSE +21 -0
- package/README.md +162 -0
- package/dist/cli/args.d.ts +42 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +262 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +114 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/output.d.ts +22 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +105 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cookies/jar.d.ts +41 -0
- package/dist/cookies/jar.d.ts.map +1 -0
- package/dist/cookies/jar.js +148 -0
- package/dist/cookies/jar.js.map +1 -0
- package/dist/cookies/parser.d.ts +24 -0
- package/dist/cookies/parser.d.ts.map +1 -0
- package/dist/cookies/parser.js +93 -0
- package/dist/cookies/parser.js.map +1 -0
- package/dist/core/client.d.ts +79 -0
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/client.js +106 -0
- package/dist/core/client.js.map +1 -0
- package/dist/core/errors.d.ts +36 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +65 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/request.d.ts +96 -0
- package/dist/core/request.d.ts.map +1 -0
- package/dist/core/request.js +5 -0
- package/dist/core/request.js.map +1 -0
- package/dist/core/response.d.ts +48 -0
- package/dist/core/response.d.ts.map +1 -0
- package/dist/core/response.js +65 -0
- package/dist/core/response.js.map +1 -0
- package/dist/core/session.d.ts +60 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +305 -0
- package/dist/core/session.js.map +1 -0
- package/dist/fingerprints/akamai.d.ts +17 -0
- package/dist/fingerprints/akamai.d.ts.map +1 -0
- package/dist/fingerprints/akamai.js +30 -0
- package/dist/fingerprints/akamai.js.map +1 -0
- package/dist/fingerprints/database.d.ts +33 -0
- package/dist/fingerprints/database.d.ts.map +1 -0
- package/dist/fingerprints/database.js +68 -0
- package/dist/fingerprints/database.js.map +1 -0
- package/dist/fingerprints/extensions.d.ts +49 -0
- package/dist/fingerprints/extensions.d.ts.map +1 -0
- package/dist/fingerprints/extensions.js +178 -0
- package/dist/fingerprints/extensions.js.map +1 -0
- package/dist/fingerprints/ja3.d.ts +32 -0
- package/dist/fingerprints/ja3.d.ts.map +1 -0
- package/dist/fingerprints/ja3.js +64 -0
- package/dist/fingerprints/ja3.js.map +1 -0
- package/dist/fingerprints/profiles/chrome.d.ts +30 -0
- package/dist/fingerprints/profiles/chrome.d.ts.map +1 -0
- package/dist/fingerprints/profiles/chrome.js +202 -0
- package/dist/fingerprints/profiles/chrome.js.map +1 -0
- package/dist/fingerprints/profiles/edge.d.ts +16 -0
- package/dist/fingerprints/profiles/edge.d.ts.map +1 -0
- package/dist/fingerprints/profiles/edge.js +61 -0
- package/dist/fingerprints/profiles/edge.js.map +1 -0
- package/dist/fingerprints/profiles/firefox.d.ts +13 -0
- package/dist/fingerprints/profiles/firefox.d.ts.map +1 -0
- package/dist/fingerprints/profiles/firefox.js +160 -0
- package/dist/fingerprints/profiles/firefox.js.map +1 -0
- package/dist/fingerprints/profiles/safari.d.ts +16 -0
- package/dist/fingerprints/profiles/safari.d.ts.map +1 -0
- package/dist/fingerprints/profiles/safari.js +140 -0
- package/dist/fingerprints/profiles/safari.js.map +1 -0
- package/dist/fingerprints/profiles/tor.d.ts +14 -0
- package/dist/fingerprints/profiles/tor.d.ts.map +1 -0
- package/dist/fingerprints/profiles/tor.js +136 -0
- package/dist/fingerprints/profiles/tor.js.map +1 -0
- package/dist/fingerprints/types.d.ts +104 -0
- package/dist/fingerprints/types.d.ts.map +1 -0
- package/dist/fingerprints/types.js +9 -0
- package/dist/fingerprints/types.js.map +1 -0
- package/dist/http/h1/client.d.ts +21 -0
- package/dist/http/h1/client.d.ts.map +1 -0
- package/dist/http/h1/client.js +136 -0
- package/dist/http/h1/client.js.map +1 -0
- package/dist/http/h1/encoder.d.ts +11 -0
- package/dist/http/h1/encoder.d.ts.map +1 -0
- package/dist/http/h1/encoder.js +75 -0
- package/dist/http/h1/encoder.js.map +1 -0
- package/dist/http/h1/parser.d.ts +61 -0
- package/dist/http/h1/parser.d.ts.map +1 -0
- package/dist/http/h1/parser.js +258 -0
- package/dist/http/h1/parser.js.map +1 -0
- package/dist/http/h2/client.d.ts +48 -0
- package/dist/http/h2/client.d.ts.map +1 -0
- package/dist/http/h2/client.js +376 -0
- package/dist/http/h2/client.js.map +1 -0
- package/dist/http/h2/frames.d.ts +65 -0
- package/dist/http/h2/frames.d.ts.map +1 -0
- package/dist/http/h2/frames.js +184 -0
- package/dist/http/h2/frames.js.map +1 -0
- package/dist/http/h2/hpack.d.ts +27 -0
- package/dist/http/h2/hpack.d.ts.map +1 -0
- package/dist/http/h2/hpack.js +423 -0
- package/dist/http/h2/hpack.js.map +1 -0
- package/dist/http/negotiator.d.ts +36 -0
- package/dist/http/negotiator.d.ts.map +1 -0
- package/dist/http/negotiator.js +101 -0
- package/dist/http/negotiator.js.map +1 -0
- package/dist/http/pool.d.ts +63 -0
- package/dist/http/pool.d.ts.map +1 -0
- package/dist/http/pool.js +177 -0
- package/dist/http/pool.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/interceptor.d.ts +27 -0
- package/dist/middleware/interceptor.d.ts.map +1 -0
- package/dist/middleware/interceptor.js +35 -0
- package/dist/middleware/interceptor.js.map +1 -0
- package/dist/middleware/rate-limiter.d.ts +26 -0
- package/dist/middleware/rate-limiter.d.ts.map +1 -0
- package/dist/middleware/rate-limiter.js +59 -0
- package/dist/middleware/rate-limiter.js.map +1 -0
- package/dist/middleware/retry.d.ts +17 -0
- package/dist/middleware/retry.d.ts.map +1 -0
- package/dist/middleware/retry.js +64 -0
- package/dist/middleware/retry.js.map +1 -0
- package/dist/proxy/http-proxy.d.ts +23 -0
- package/dist/proxy/http-proxy.d.ts.map +1 -0
- package/dist/proxy/http-proxy.js +93 -0
- package/dist/proxy/http-proxy.js.map +1 -0
- package/dist/proxy/socks.d.ts +24 -0
- package/dist/proxy/socks.d.ts.map +1 -0
- package/dist/proxy/socks.js +196 -0
- package/dist/proxy/socks.js.map +1 -0
- package/dist/tls/constants.d.ts +142 -0
- package/dist/tls/constants.d.ts.map +1 -0
- package/dist/tls/constants.js +163 -0
- package/dist/tls/constants.js.map +1 -0
- package/dist/tls/node-engine.d.ts +22 -0
- package/dist/tls/node-engine.d.ts.map +1 -0
- package/dist/tls/node-engine.js +190 -0
- package/dist/tls/node-engine.js.map +1 -0
- package/dist/tls/stealth/client-hello.d.ts +38 -0
- package/dist/tls/stealth/client-hello.d.ts.map +1 -0
- package/dist/tls/stealth/client-hello.js +197 -0
- package/dist/tls/stealth/client-hello.js.map +1 -0
- package/dist/tls/stealth/engine.d.ts +16 -0
- package/dist/tls/stealth/engine.d.ts.map +1 -0
- package/dist/tls/stealth/engine.js +196 -0
- package/dist/tls/stealth/engine.js.map +1 -0
- package/dist/tls/stealth/handshake.d.ts +45 -0
- package/dist/tls/stealth/handshake.d.ts.map +1 -0
- package/dist/tls/stealth/handshake.js +403 -0
- package/dist/tls/stealth/handshake.js.map +1 -0
- package/dist/tls/stealth/key-schedule.d.ts +85 -0
- package/dist/tls/stealth/key-schedule.d.ts.map +1 -0
- package/dist/tls/stealth/key-schedule.js +141 -0
- package/dist/tls/stealth/key-schedule.js.map +1 -0
- package/dist/tls/stealth/record-layer.d.ts +74 -0
- package/dist/tls/stealth/record-layer.d.ts.map +1 -0
- package/dist/tls/stealth/record-layer.js +167 -0
- package/dist/tls/stealth/record-layer.js.map +1 -0
- package/dist/tls/types.d.ts +58 -0
- package/dist/tls/types.d.ts.map +1 -0
- package/dist/tls/types.js +6 -0
- package/dist/tls/types.js.map +1 -0
- package/dist/utils/buffer-reader.d.ts +32 -0
- package/dist/utils/buffer-reader.d.ts.map +1 -0
- package/dist/utils/buffer-reader.js +99 -0
- package/dist/utils/buffer-reader.js.map +1 -0
- package/dist/utils/buffer-writer.d.ts +35 -0
- package/dist/utils/buffer-writer.d.ts.map +1 -0
- package/dist/utils/buffer-writer.js +121 -0
- package/dist/utils/buffer-writer.js.map +1 -0
- package/dist/utils/encoding.d.ts +19 -0
- package/dist/utils/encoding.d.ts.map +1 -0
- package/dist/utils/encoding.js +63 -0
- package/dist/utils/encoding.js.map +1 -0
- package/dist/utils/logger.d.ts +24 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +56 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/url.d.ts +22 -0
- package/dist/utils/url.d.ts.map +1 -0
- package/dist/utils/url.js +56 -0
- package/dist/utils/url.js.map +1 -0
- package/dist/ws/client.d.ts +63 -0
- package/dist/ws/client.d.ts.map +1 -0
- package/dist/ws/client.js +273 -0
- package/dist/ws/client.js.map +1 -0
- package/dist/ws/frame.d.ts +44 -0
- package/dist/ws/frame.d.ts.map +1 -0
- package/dist/ws/frame.js +146 -0
- package/dist/ws/frame.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI output formatting.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Format and write response output to stdout/stderr.
|
|
6
|
+
*/
|
|
7
|
+
export function formatOutput(response, args) {
|
|
8
|
+
const parts = [];
|
|
9
|
+
// Include response headers (-i / --include)
|
|
10
|
+
if (args.include || args.verbose) {
|
|
11
|
+
parts.push(formatResponseHeaders(response));
|
|
12
|
+
parts.push('');
|
|
13
|
+
}
|
|
14
|
+
// HEAD request: no body
|
|
15
|
+
if (args.head) {
|
|
16
|
+
return parts.join('\n');
|
|
17
|
+
}
|
|
18
|
+
// Body
|
|
19
|
+
const body = response.text();
|
|
20
|
+
parts.push(body);
|
|
21
|
+
return parts.join('\n');
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Format the response status line and headers.
|
|
25
|
+
*/
|
|
26
|
+
export function formatResponseHeaders(response) {
|
|
27
|
+
const lines = [];
|
|
28
|
+
// Status line
|
|
29
|
+
lines.push(`HTTP/${response.httpVersion} ${response.status} ${response.statusText}`);
|
|
30
|
+
// Headers
|
|
31
|
+
for (const [key, value] of Object.entries(response.headers)) {
|
|
32
|
+
lines.push(`${key}: ${value}`);
|
|
33
|
+
}
|
|
34
|
+
return lines.join('\n');
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Format verbose request info (written to stderr).
|
|
38
|
+
*/
|
|
39
|
+
export function formatVerboseRequest(method, url, headers) {
|
|
40
|
+
const parsed = new URL(url);
|
|
41
|
+
const lines = [];
|
|
42
|
+
lines.push(`> ${method} ${parsed.pathname}${parsed.search} HTTP/1.1`);
|
|
43
|
+
lines.push(`> Host: ${parsed.host}`);
|
|
44
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
45
|
+
lines.push(`> ${key}: ${value}`);
|
|
46
|
+
}
|
|
47
|
+
lines.push('>');
|
|
48
|
+
return lines.join('\n');
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Print the help text.
|
|
52
|
+
*/
|
|
53
|
+
export function printHelp() {
|
|
54
|
+
return `nlcurl -- HTTP client with browser fingerprint impersonation
|
|
55
|
+
|
|
56
|
+
USAGE:
|
|
57
|
+
nlcurl [OPTIONS] <URL>
|
|
58
|
+
|
|
59
|
+
OPTIONS:
|
|
60
|
+
-X, --request <METHOD> HTTP method (GET, POST, PUT, DELETE, etc.)
|
|
61
|
+
-H, --header <HEADER> Add a request header (Name: Value)
|
|
62
|
+
-d, --data <DATA> Request body (sets method to POST if not specified)
|
|
63
|
+
--data-raw <DATA> Request body without special character processing
|
|
64
|
+
-A, --user-agent <AGENT> Set the User-Agent header
|
|
65
|
+
-o, --output <FILE> Write response body to file
|
|
66
|
+
-I, --head Send HEAD request, show headers only
|
|
67
|
+
-i, --include Include response headers in output
|
|
68
|
+
-v, --verbose Verbose output (request and response details)
|
|
69
|
+
-s, --silent Suppress progress and error messages
|
|
70
|
+
--compressed Request compressed response
|
|
71
|
+
|
|
72
|
+
IMPERSONATION:
|
|
73
|
+
--impersonate <PROFILE> Browser profile (e.g. chrome136, firefox138)
|
|
74
|
+
--stealth Use stealth TLS engine for full fingerprint control
|
|
75
|
+
--ja3 <FINGERPRINT> Custom JA3 fingerprint string
|
|
76
|
+
--akamai <FINGERPRINT> Custom Akamai HTTP/2 fingerprint string
|
|
77
|
+
--list-profiles List all available browser profiles
|
|
78
|
+
|
|
79
|
+
CONNECTION:
|
|
80
|
+
-x, --proxy <URL> Proxy URL (http, socks4, socks5)
|
|
81
|
+
-U, --proxy-user <USER:PASS> Proxy authentication
|
|
82
|
+
-k, --insecure Skip TLS certificate verification
|
|
83
|
+
-L, --location Follow redirects (default)
|
|
84
|
+
--no-location Do not follow redirects
|
|
85
|
+
--max-redirs <NUM> Maximum number of redirects (default: 20)
|
|
86
|
+
-m, --max-time <SECONDS> Maximum request time in seconds
|
|
87
|
+
--http1.1 Force HTTP/1.1
|
|
88
|
+
--http2 Force HTTP/2
|
|
89
|
+
|
|
90
|
+
COOKIES:
|
|
91
|
+
-b, --cookie <DATA> Send cookies (name=value pairs)
|
|
92
|
+
-c, --cookie-jar <FILE> Write received cookies to file
|
|
93
|
+
|
|
94
|
+
META:
|
|
95
|
+
-h, --help Show this help message
|
|
96
|
+
-V, --version Show version
|
|
97
|
+
|
|
98
|
+
EXAMPLES:
|
|
99
|
+
nlcurl https://httpbin.org/get
|
|
100
|
+
nlcurl --impersonate chrome136 https://tls.browserleaks.com/json
|
|
101
|
+
nlcurl --stealth --impersonate firefox138 https://example.com
|
|
102
|
+
nlcurl -X POST -d '{"key":"value"}' -H "Content-Type: application/json" https://api.example.com
|
|
103
|
+
nlcurl -x socks5://127.0.0.1:1080 --impersonate chrome https://ifconfig.me`;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;GAEG;AACH,MAAM,UAAU,YAAY,CAC1B,QAAwB,EACxB,IAAgB;IAEhB,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,4CAA4C;IAC5C,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC5C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,wBAAwB;IACxB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,OAAO;IACP,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC7B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEjB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAwB;IAC5D,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,cAAc;IACd,KAAK,CAAC,IAAI,CAAC,QAAQ,QAAQ,CAAC,WAAW,IAAI,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IAErF,UAAU;IACV,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5D,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,KAAK,KAAK,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAAc,EACd,GAAW,EACX,OAA+B;IAE/B,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,MAAM,WAAW,CAAC,CAAC;IACtE,KAAK,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAErC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,KAAK,EAAE,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+EAiDsE,CAAC;AAChF,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cookie jar (RFC 6265).
|
|
3
|
+
*
|
|
4
|
+
* Thread-safe, in-memory cookie storage with domain/path matching
|
|
5
|
+
* and expiration handling.
|
|
6
|
+
*/
|
|
7
|
+
import { type Cookie } from './parser.js';
|
|
8
|
+
export declare class CookieJar {
|
|
9
|
+
private cookies;
|
|
10
|
+
/**
|
|
11
|
+
* Store cookies from Set-Cookie response headers.
|
|
12
|
+
*
|
|
13
|
+
* Accepts either a flat Record (with optional rawHeaders for proper
|
|
14
|
+
* multi-value handling) or processes the merged header value.
|
|
15
|
+
*/
|
|
16
|
+
setCookies(headers: Record<string, string>, requestUrl: URL, rawHeaders?: Array<[string, string]>): void;
|
|
17
|
+
/**
|
|
18
|
+
* Get the Cookie header value for a request URL.
|
|
19
|
+
* Returns empty string if no cookies match.
|
|
20
|
+
*/
|
|
21
|
+
getCookieHeader(url: URL): string;
|
|
22
|
+
/**
|
|
23
|
+
* Clear all cookies.
|
|
24
|
+
*/
|
|
25
|
+
clear(): void;
|
|
26
|
+
/**
|
|
27
|
+
* Clear cookies for a specific domain.
|
|
28
|
+
*/
|
|
29
|
+
clearDomain(domain: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Get all stored cookies (for inspection/debugging).
|
|
32
|
+
*/
|
|
33
|
+
all(): ReadonlyArray<Cookie>;
|
|
34
|
+
get size(): number;
|
|
35
|
+
private store;
|
|
36
|
+
private matches;
|
|
37
|
+
private domainMatches;
|
|
38
|
+
private pathMatches;
|
|
39
|
+
private extractSetCookieValues;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=jar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jar.d.ts","sourceRoot":"","sources":["../../src/cookies/jar.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAoC,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAM5E,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAgB;IAE/B;;;;;OAKG;IACH,UAAU,CACR,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,UAAU,EAAE,GAAG,EACf,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACnC,IAAI;IAWP;;;OAGG;IACH,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM;IAcjC;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIjC;;OAEG;IACH,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC;IAI5B,IAAI,IAAI,IAAI,MAAM,CAEjB;IAID,OAAO,CAAC,KAAK;IA+Bb,OAAO,CAAC,OAAO;IAoBf,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,sBAAsB;CAmB/B"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cookie jar (RFC 6265).
|
|
3
|
+
*
|
|
4
|
+
* Thread-safe, in-memory cookie storage with domain/path matching
|
|
5
|
+
* and expiration handling.
|
|
6
|
+
*/
|
|
7
|
+
import { parseSetCookie, serializeCookies } from './parser.js';
|
|
8
|
+
/** Maximum number of cookies stored (per RFC 6265 §6.1 guidance). */
|
|
9
|
+
const MAX_COOKIES = 3000;
|
|
10
|
+
const MAX_COOKIES_PER_DOMAIN = 50;
|
|
11
|
+
export class CookieJar {
|
|
12
|
+
cookies = [];
|
|
13
|
+
/**
|
|
14
|
+
* Store cookies from Set-Cookie response headers.
|
|
15
|
+
*
|
|
16
|
+
* Accepts either a flat Record (with optional rawHeaders for proper
|
|
17
|
+
* multi-value handling) or processes the merged header value.
|
|
18
|
+
*/
|
|
19
|
+
setCookies(headers, requestUrl, rawHeaders) {
|
|
20
|
+
const setCookieValues = this.extractSetCookieValues(headers, rawHeaders);
|
|
21
|
+
for (const value of setCookieValues) {
|
|
22
|
+
const cookie = parseSetCookie(value, requestUrl);
|
|
23
|
+
if (cookie) {
|
|
24
|
+
this.store(cookie);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get the Cookie header value for a request URL.
|
|
30
|
+
* Returns empty string if no cookies match.
|
|
31
|
+
*/
|
|
32
|
+
getCookieHeader(url) {
|
|
33
|
+
const now = Date.now();
|
|
34
|
+
const matching = this.cookies.filter((c) => this.matches(c, url, now));
|
|
35
|
+
if (matching.length === 0)
|
|
36
|
+
return '';
|
|
37
|
+
// Sort by path length (longest first), then creation time (earliest first)
|
|
38
|
+
matching.sort((a, b) => {
|
|
39
|
+
if (a.path.length !== b.path.length)
|
|
40
|
+
return b.path.length - a.path.length;
|
|
41
|
+
return a.createdAt - b.createdAt;
|
|
42
|
+
});
|
|
43
|
+
return serializeCookies(matching);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Clear all cookies.
|
|
47
|
+
*/
|
|
48
|
+
clear() {
|
|
49
|
+
this.cookies = [];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Clear cookies for a specific domain.
|
|
53
|
+
*/
|
|
54
|
+
clearDomain(domain) {
|
|
55
|
+
this.cookies = this.cookies.filter((c) => c.domain !== domain.toLowerCase());
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get all stored cookies (for inspection/debugging).
|
|
59
|
+
*/
|
|
60
|
+
all() {
|
|
61
|
+
return this.cookies;
|
|
62
|
+
}
|
|
63
|
+
get size() {
|
|
64
|
+
return this.cookies.length;
|
|
65
|
+
}
|
|
66
|
+
// ---- Internal ----
|
|
67
|
+
store(cookie) {
|
|
68
|
+
// Max-Age = 0 means delete
|
|
69
|
+
if (cookie.maxAge !== undefined && cookie.maxAge <= 0) {
|
|
70
|
+
this.cookies = this.cookies.filter((c) => !(c.name === cookie.name && c.domain === cookie.domain && c.path === cookie.path));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// Replace existing cookie with same name/domain/path
|
|
74
|
+
const idx = this.cookies.findIndex((c) => c.name === cookie.name && c.domain === cookie.domain && c.path === cookie.path);
|
|
75
|
+
if (idx >= 0) {
|
|
76
|
+
this.cookies[idx] = cookie;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Enforce per-domain limit
|
|
80
|
+
const domainCount = this.cookies.filter((c) => c.domain === cookie.domain).length;
|
|
81
|
+
if (domainCount >= MAX_COOKIES_PER_DOMAIN) {
|
|
82
|
+
// Evict oldest cookie for this domain
|
|
83
|
+
const oldest = this.cookies.findIndex((c) => c.domain === cookie.domain);
|
|
84
|
+
if (oldest >= 0)
|
|
85
|
+
this.cookies.splice(oldest, 1);
|
|
86
|
+
}
|
|
87
|
+
// Enforce global limit
|
|
88
|
+
if (this.cookies.length >= MAX_COOKIES) {
|
|
89
|
+
this.cookies.shift();
|
|
90
|
+
}
|
|
91
|
+
this.cookies.push(cookie);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
matches(cookie, url, now) {
|
|
95
|
+
// Check expiration
|
|
96
|
+
if (cookie.maxAge !== undefined) {
|
|
97
|
+
if (now > cookie.createdAt + cookie.maxAge * 1000)
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
if (cookie.expires && now > cookie.expires.getTime())
|
|
101
|
+
return false;
|
|
102
|
+
// Domain matching
|
|
103
|
+
const host = url.hostname.toLowerCase();
|
|
104
|
+
if (!this.domainMatches(host, cookie.domain))
|
|
105
|
+
return false;
|
|
106
|
+
// Path matching
|
|
107
|
+
if (!this.pathMatches(url.pathname, cookie.path))
|
|
108
|
+
return false;
|
|
109
|
+
// Secure flag
|
|
110
|
+
if (cookie.secure && url.protocol !== 'https:')
|
|
111
|
+
return false;
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
domainMatches(host, domain) {
|
|
115
|
+
if (host === domain)
|
|
116
|
+
return true;
|
|
117
|
+
// Host must end with .domain
|
|
118
|
+
return host.endsWith('.' + domain);
|
|
119
|
+
}
|
|
120
|
+
pathMatches(requestPath, cookiePath) {
|
|
121
|
+
if (requestPath === cookiePath)
|
|
122
|
+
return true;
|
|
123
|
+
if (requestPath.startsWith(cookiePath)) {
|
|
124
|
+
if (cookiePath.endsWith('/'))
|
|
125
|
+
return true;
|
|
126
|
+
if (requestPath[cookiePath.length] === '/')
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
extractSetCookieValues(headers, rawHeaders) {
|
|
132
|
+
// Prefer raw headers to preserve individual Set-Cookie values
|
|
133
|
+
if (rawHeaders) {
|
|
134
|
+
return rawHeaders
|
|
135
|
+
.filter(([k]) => k.toLowerCase() === 'set-cookie')
|
|
136
|
+
.map(([, v]) => v);
|
|
137
|
+
}
|
|
138
|
+
// Fallback: extract from merged Record
|
|
139
|
+
const values = [];
|
|
140
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
141
|
+
if (key.toLowerCase() === 'set-cookie') {
|
|
142
|
+
values.push(value);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return values;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=jar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jar.js","sourceRoot":"","sources":["../../src/cookies/jar.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cookie parser and serializer (RFC 6265).
|
|
3
|
+
*/
|
|
4
|
+
export interface Cookie {
|
|
5
|
+
name: string;
|
|
6
|
+
value: string;
|
|
7
|
+
domain: string;
|
|
8
|
+
path: string;
|
|
9
|
+
expires?: Date;
|
|
10
|
+
maxAge?: number;
|
|
11
|
+
secure: boolean;
|
|
12
|
+
httpOnly: boolean;
|
|
13
|
+
sameSite?: 'strict' | 'lax' | 'none';
|
|
14
|
+
createdAt: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Parse a Set-Cookie header value into a Cookie object.
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseSetCookie(header: string, requestUrl: URL): Cookie | null;
|
|
20
|
+
/**
|
|
21
|
+
* Serialize cookies for the Cookie header.
|
|
22
|
+
*/
|
|
23
|
+
export declare function serializeCookies(cookies: Cookie[]): string;
|
|
24
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/cookies/parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IACrC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,CA0E7E;AASD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAE1D"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cookie parser and serializer (RFC 6265).
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Parse a Set-Cookie header value into a Cookie object.
|
|
6
|
+
*/
|
|
7
|
+
export function parseSetCookie(header, requestUrl) {
|
|
8
|
+
const parts = header.split(';').map((s) => s.trim());
|
|
9
|
+
if (parts.length === 0)
|
|
10
|
+
return null;
|
|
11
|
+
const nameValue = parts[0];
|
|
12
|
+
const eqIdx = nameValue.indexOf('=');
|
|
13
|
+
if (eqIdx < 0)
|
|
14
|
+
return null;
|
|
15
|
+
const name = nameValue.substring(0, eqIdx).trim();
|
|
16
|
+
const value = nameValue.substring(eqIdx + 1).trim();
|
|
17
|
+
if (!name)
|
|
18
|
+
return null;
|
|
19
|
+
const cookie = {
|
|
20
|
+
name,
|
|
21
|
+
value,
|
|
22
|
+
domain: requestUrl.hostname,
|
|
23
|
+
path: defaultPath(requestUrl.pathname),
|
|
24
|
+
secure: false,
|
|
25
|
+
httpOnly: false,
|
|
26
|
+
createdAt: Date.now(),
|
|
27
|
+
};
|
|
28
|
+
for (let i = 1; i < parts.length; i++) {
|
|
29
|
+
const attr = parts[i];
|
|
30
|
+
const attrEq = attr.indexOf('=');
|
|
31
|
+
const attrName = (attrEq >= 0 ? attr.substring(0, attrEq) : attr)
|
|
32
|
+
.trim()
|
|
33
|
+
.toLowerCase();
|
|
34
|
+
const attrValue = attrEq >= 0 ? attr.substring(attrEq + 1).trim() : '';
|
|
35
|
+
switch (attrName) {
|
|
36
|
+
case 'domain': {
|
|
37
|
+
let d = attrValue.toLowerCase();
|
|
38
|
+
if (d.startsWith('.'))
|
|
39
|
+
d = d.substring(1);
|
|
40
|
+
// Validate domain matches request host (RFC 6265 §5.3.6)
|
|
41
|
+
const host = requestUrl.hostname.toLowerCase();
|
|
42
|
+
if (d !== host && !host.endsWith('.' + d)) {
|
|
43
|
+
// Reject cookie — domain doesn't match request
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
cookie.domain = d;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
case 'path':
|
|
50
|
+
cookie.path = attrValue || '/';
|
|
51
|
+
break;
|
|
52
|
+
case 'expires': {
|
|
53
|
+
const date = new Date(attrValue);
|
|
54
|
+
if (!Number.isNaN(date.getTime())) {
|
|
55
|
+
cookie.expires = date;
|
|
56
|
+
}
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
case 'max-age': {
|
|
60
|
+
const secs = parseInt(attrValue, 10);
|
|
61
|
+
if (!Number.isNaN(secs)) {
|
|
62
|
+
cookie.maxAge = secs;
|
|
63
|
+
}
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
case 'secure':
|
|
67
|
+
cookie.secure = true;
|
|
68
|
+
break;
|
|
69
|
+
case 'httponly':
|
|
70
|
+
cookie.httpOnly = true;
|
|
71
|
+
break;
|
|
72
|
+
case 'samesite':
|
|
73
|
+
cookie.sameSite = attrValue.toLowerCase();
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return cookie;
|
|
78
|
+
}
|
|
79
|
+
function defaultPath(path) {
|
|
80
|
+
if (!path || !path.startsWith('/'))
|
|
81
|
+
return '/';
|
|
82
|
+
const lastSlash = path.lastIndexOf('/');
|
|
83
|
+
if (lastSlash === 0)
|
|
84
|
+
return '/';
|
|
85
|
+
return path.substring(0, lastSlash);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Serialize cookies for the Cookie header.
|
|
89
|
+
*/
|
|
90
|
+
export function serializeCookies(cookies) {
|
|
91
|
+
return cookies.map((c) => `${c.name}=${c.value}`).join('; ');
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/cookies/parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NLcURL client.
|
|
3
|
+
*
|
|
4
|
+
* The primary public interface for making HTTP requests with browser
|
|
5
|
+
* fingerprint impersonation. Provides both a session-based API for
|
|
6
|
+
* persistent connections and cookie handling, and standalone convenience
|
|
7
|
+
* functions for one-off requests.
|
|
8
|
+
*/
|
|
9
|
+
import type { NLcURLRequest, NLcURLSessionConfig, RequestBody } from './request.js';
|
|
10
|
+
import { NLcURLResponse } from './response.js';
|
|
11
|
+
import { NLcURLSession, type RequestOptions } from './session.js';
|
|
12
|
+
/**
|
|
13
|
+
* Create a new persistent session.
|
|
14
|
+
*
|
|
15
|
+
* Sessions maintain a connection pool, cookie jar, and default
|
|
16
|
+
* configuration across multiple requests.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const session = createSession({ impersonate: 'chrome136' });
|
|
21
|
+
* const response = await session.get('https://httpbin.org/get');
|
|
22
|
+
* console.log(response.json());
|
|
23
|
+
* session.close();
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function createSession(config?: NLcURLSessionConfig): NLcURLSession;
|
|
27
|
+
/**
|
|
28
|
+
* Send an HTTP request.
|
|
29
|
+
*
|
|
30
|
+
* Creates a temporary session, sends the request, and closes the session.
|
|
31
|
+
* For multiple requests, use `createSession()` instead for better
|
|
32
|
+
* performance via connection reuse.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* const resp = await request({
|
|
37
|
+
* url: 'https://httpbin.org/get',
|
|
38
|
+
* impersonate: 'chrome136',
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function request(input: NLcURLRequest): Promise<NLcURLResponse>;
|
|
43
|
+
/**
|
|
44
|
+
* Send a GET request.
|
|
45
|
+
*/
|
|
46
|
+
export declare function get(url: string, options?: RequestOptions & {
|
|
47
|
+
impersonate?: string;
|
|
48
|
+
}): Promise<NLcURLResponse>;
|
|
49
|
+
/**
|
|
50
|
+
* Send a POST request.
|
|
51
|
+
*/
|
|
52
|
+
export declare function post(url: string, body?: RequestBody, options?: RequestOptions & {
|
|
53
|
+
impersonate?: string;
|
|
54
|
+
}): Promise<NLcURLResponse>;
|
|
55
|
+
/**
|
|
56
|
+
* Send a PUT request.
|
|
57
|
+
*/
|
|
58
|
+
export declare function put(url: string, body?: RequestBody, options?: RequestOptions & {
|
|
59
|
+
impersonate?: string;
|
|
60
|
+
}): Promise<NLcURLResponse>;
|
|
61
|
+
/**
|
|
62
|
+
* Send a PATCH request.
|
|
63
|
+
*/
|
|
64
|
+
export declare function patch(url: string, body?: RequestBody, options?: RequestOptions & {
|
|
65
|
+
impersonate?: string;
|
|
66
|
+
}): Promise<NLcURLResponse>;
|
|
67
|
+
/**
|
|
68
|
+
* Send a DELETE request.
|
|
69
|
+
*/
|
|
70
|
+
export declare function del(url: string, options?: RequestOptions & {
|
|
71
|
+
impersonate?: string;
|
|
72
|
+
}): Promise<NLcURLResponse>;
|
|
73
|
+
/**
|
|
74
|
+
* Send a HEAD request.
|
|
75
|
+
*/
|
|
76
|
+
export declare function head(url: string, options?: RequestOptions & {
|
|
77
|
+
impersonate?: string;
|
|
78
|
+
}): Promise<NLcURLResponse>;
|
|
79
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,aAAa,EACb,mBAAmB,EACnB,WAAW,EACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAElE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,MAAM,CAAC,EAAE,mBAAmB,GAAG,aAAa,CAEzE;AAID;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAO3E;AAED;;GAEG;AACH,wBAAsB,GAAG,CACvB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,cAAc,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAClD,OAAO,CAAC,cAAc,CAAC,CAEzB;AAED;;GAEG;AACH,wBAAsB,IAAI,CACxB,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,WAAW,EAClB,OAAO,CAAC,EAAE,cAAc,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAClD,OAAO,CAAC,cAAc,CAAC,CAEzB;AAED;;GAEG;AACH,wBAAsB,GAAG,CACvB,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,WAAW,EAClB,OAAO,CAAC,EAAE,cAAc,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAClD,OAAO,CAAC,cAAc,CAAC,CAEzB;AAED;;GAEG;AACH,wBAAsB,KAAK,CACzB,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,WAAW,EAClB,OAAO,CAAC,EAAE,cAAc,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAClD,OAAO,CAAC,cAAc,CAAC,CAEzB;AAED;;GAEG;AACH,wBAAsB,GAAG,CACvB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,cAAc,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAClD,OAAO,CAAC,cAAc,CAAC,CAEzB;AAED;;GAEG;AACH,wBAAsB,IAAI,CACxB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,cAAc,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAClD,OAAO,CAAC,cAAc,CAAC,CAEzB"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NLcURL client.
|
|
3
|
+
*
|
|
4
|
+
* The primary public interface for making HTTP requests with browser
|
|
5
|
+
* fingerprint impersonation. Provides both a session-based API for
|
|
6
|
+
* persistent connections and cookie handling, and standalone convenience
|
|
7
|
+
* functions for one-off requests.
|
|
8
|
+
*/
|
|
9
|
+
import { NLcURLSession } from './session.js';
|
|
10
|
+
/**
|
|
11
|
+
* Create a new persistent session.
|
|
12
|
+
*
|
|
13
|
+
* Sessions maintain a connection pool, cookie jar, and default
|
|
14
|
+
* configuration across multiple requests.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* const session = createSession({ impersonate: 'chrome136' });
|
|
19
|
+
* const response = await session.get('https://httpbin.org/get');
|
|
20
|
+
* console.log(response.json());
|
|
21
|
+
* session.close();
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function createSession(config) {
|
|
25
|
+
return new NLcURLSession(config);
|
|
26
|
+
}
|
|
27
|
+
// ---- One-shot request functions ----
|
|
28
|
+
/**
|
|
29
|
+
* Send an HTTP request.
|
|
30
|
+
*
|
|
31
|
+
* Creates a temporary session, sends the request, and closes the session.
|
|
32
|
+
* For multiple requests, use `createSession()` instead for better
|
|
33
|
+
* performance via connection reuse.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* const resp = await request({
|
|
38
|
+
* url: 'https://httpbin.org/get',
|
|
39
|
+
* impersonate: 'chrome136',
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export async function request(input) {
|
|
44
|
+
const session = new NLcURLSession(extractSessionConfig(input));
|
|
45
|
+
try {
|
|
46
|
+
return await session.request(input);
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
session.close();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Send a GET request.
|
|
54
|
+
*/
|
|
55
|
+
export async function get(url, options) {
|
|
56
|
+
return request({ ...options, url, method: 'GET' });
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Send a POST request.
|
|
60
|
+
*/
|
|
61
|
+
export async function post(url, body, options) {
|
|
62
|
+
return request({ ...options, url, method: 'POST', body });
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Send a PUT request.
|
|
66
|
+
*/
|
|
67
|
+
export async function put(url, body, options) {
|
|
68
|
+
return request({ ...options, url, method: 'PUT', body });
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Send a PATCH request.
|
|
72
|
+
*/
|
|
73
|
+
export async function patch(url, body, options) {
|
|
74
|
+
return request({ ...options, url, method: 'PATCH', body });
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Send a DELETE request.
|
|
78
|
+
*/
|
|
79
|
+
export async function del(url, options) {
|
|
80
|
+
return request({ ...options, url, method: 'DELETE' });
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Send a HEAD request.
|
|
84
|
+
*/
|
|
85
|
+
export async function head(url, options) {
|
|
86
|
+
return request({ ...options, url, method: 'HEAD' });
|
|
87
|
+
}
|
|
88
|
+
// ---- Internal ----
|
|
89
|
+
/**
|
|
90
|
+
* Extract session-level configuration from a request object.
|
|
91
|
+
*/
|
|
92
|
+
function extractSessionConfig(req) {
|
|
93
|
+
return {
|
|
94
|
+
impersonate: req.impersonate,
|
|
95
|
+
ja3: req.ja3,
|
|
96
|
+
akamai: req.akamai,
|
|
97
|
+
stealth: req.stealth,
|
|
98
|
+
proxy: req.proxy,
|
|
99
|
+
proxyAuth: req.proxyAuth,
|
|
100
|
+
insecure: req.insecure,
|
|
101
|
+
httpVersion: req.httpVersion,
|
|
102
|
+
timeout: req.timeout,
|
|
103
|
+
acceptEncoding: req.acceptEncoding,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,OAAO,EAAE,aAAa,EAAuB,MAAM,cAAc,CAAC;AAElE;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,aAAa,CAAC,MAA4B;IACxD,OAAO,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC;AAED,uCAAuC;AAEvC;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,KAAoB;IAChD,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/D,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,GAAW,EACX,OAAmD;IAEnD,OAAO,OAAO,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AACrD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CACxB,GAAW,EACX,IAAkB,EAClB,OAAmD;IAEnD,OAAO,OAAO,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,GAAW,EACX,IAAkB,EAClB,OAAmD;IAEnD,OAAO,OAAO,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CACzB,GAAW,EACX,IAAkB,EAClB,OAAmD;IAEnD,OAAO,OAAO,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,GAAW,EACX,OAAmD;IAEnD,OAAO,OAAO,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;AACxD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CACxB,GAAW,EACX,OAAmD;IAEnD,OAAO,OAAO,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,qBAAqB;AAErB;;GAEG;AACH,SAAS,oBAAoB,CAAC,GAAkB;IAC9C,OAAO;QACL,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,cAAc,EAAE,GAAG,CAAC,cAAc;KACnC,CAAC;AACJ,CAAC"}
|