@fastls/fastls 0.10.2 → 0.11.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 +16 -0
- package/dist/errors.d.ts +1 -0
- package/dist/errors.js +4 -1
- package/dist/fetch.d.ts +5 -0
- package/dist/fetch.js +5 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -1
- package/dist/index.mjs +1 -1
- package/dist/native.d.ts +2 -0
- package/dist/native.js +22 -3
- package/dist/profiles.d.ts +14 -0
- package/dist/profiles.js +16 -0
- package/dist/session.d.ts +6 -0
- package/dist/session.js +58 -3
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Fastls Node.js SDK
|
|
2
2
|
|
|
3
|
+
开发候选新增 Session `addressPolicy`、`profileSpec: new ProfileSpec(...)` 和
|
|
4
|
+
`httpVersion: "h3"`;Session/fetch 可选择完整 Spec 或显式协议。
|
|
5
|
+
`addressPolicy` 只能创建可信 owner,不能由 `session.fetch()` 或请求替换。
|
|
6
|
+
现有发布库不具备新能力,旧库或缺符号会明确报错,见[能力契约](../CAPABILITIES.md)。
|
|
7
|
+
|
|
8
|
+
```typescript
|
|
9
|
+
import { Session, ProfileSpec } from '@fastls/fastls';
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
const profileSpec = new ProfileSpec(JSON.parse(readFileSync('browser.json', 'utf8')));
|
|
12
|
+
const session = new Session({ profileSpec });
|
|
13
|
+
try { await session.get('https://example.com'); } finally { await session.closeAsync(); }
|
|
14
|
+
// 强制 H3 直连,不支持时不会回退到 TCP;目标须支持 H3。
|
|
15
|
+
const h3 = new Session({ httpVersion: 'h3' });
|
|
16
|
+
try { await h3.get('https://example.com'); } finally { await h3.closeAsync(); }
|
|
17
|
+
```
|
|
18
|
+
|
|
3
19
|
Node.js 22+ 的 Fastls C ABI v1 绑定,提供 Promise API、TypeScript 声明、ESM 和 CommonJS 入口。本文对应 **0.10.1**。
|
|
4
20
|
|
|
5
21
|
支持 HTTP/1.1、HTTP/2、流式上传下载、双工、SSE、WebSocket、会话 Cookie 和 HTTP/HTTPS/SOCKS 代理。网络请求由 Go 执行,通过 Koffi 在当前 Node 进程中调用;使用者无需 Python 或 RPC 服务。
|
package/dist/errors.d.ts
CHANGED
package/dist/errors.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.AbortError = exports.FastlsDecodeError = exports.FastlsTimeoutError = ex
|
|
|
4
4
|
exports.responseError = responseError;
|
|
5
5
|
class FastlsError extends Error {
|
|
6
6
|
name = "FastlsError";
|
|
7
|
+
code;
|
|
7
8
|
}
|
|
8
9
|
exports.FastlsError = FastlsError;
|
|
9
10
|
class FastlsHTTPError extends FastlsError {
|
|
@@ -36,7 +37,9 @@ function responseError(info) {
|
|
|
36
37
|
return new FastlsTimeoutError(message, (info.timeout_phase ?? "total"));
|
|
37
38
|
if (info.error_code === "decode_error")
|
|
38
39
|
return new FastlsDecodeError(message);
|
|
39
|
-
|
|
40
|
+
const error = new FastlsError(message);
|
|
41
|
+
error.code = info.error_code;
|
|
42
|
+
return error;
|
|
40
43
|
}
|
|
41
44
|
class AbortError extends FastlsError {
|
|
42
45
|
name = "AbortError";
|
package/dist/fetch.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { Session, type RequestOptions } from "./session.js";
|
|
2
|
+
import type { ProfileSpec, AddressPolicy } from "./profiles.js";
|
|
2
3
|
export interface FetchOptions extends RequestInit {
|
|
4
|
+
profileSpec?: ProfileSpec;
|
|
5
|
+
httpVersion?: "auto" | "h3";
|
|
6
|
+
/** Only standalone fetch can create a new trusted policy owner. */
|
|
7
|
+
addressPolicy?: AddressPolicy;
|
|
3
8
|
duplex?: "half";
|
|
4
9
|
profile?: string;
|
|
5
10
|
proxy?: string | null;
|
package/dist/fetch.js
CHANGED
|
@@ -11,7 +11,9 @@ async function fetchWithSession(session, input, init = {}, owned = false) {
|
|
|
11
11
|
if (init[key] !== undefined)
|
|
12
12
|
throw new TypeError(`Fastls fetch does not support ${key}`);
|
|
13
13
|
}
|
|
14
|
-
const allowed = new Set(["method", "headers", "body", "redirect", "signal", "duplex", "profile", "proxy", "proxyCaFile", "caFile", "library", "timeoutMs", "maxRedirects"]);
|
|
14
|
+
const allowed = new Set(["method", "headers", "body", "redirect", "signal", "duplex", "profile", "profileSpec", "httpVersion", "addressPolicy", "proxy", "proxyCaFile", "caFile", "library", "timeoutMs", "maxRedirects"]);
|
|
15
|
+
if (!owned && init.addressPolicy !== undefined)
|
|
16
|
+
throw new TypeError("addressPolicy is a Session creation option");
|
|
15
17
|
for (const key of Object.keys(init))
|
|
16
18
|
if (!allowed.has(key))
|
|
17
19
|
throw new TypeError(`Fastls fetch does not support ${key}`);
|
|
@@ -29,7 +31,7 @@ async function fetchWithSession(session, input, init = {}, owned = false) {
|
|
|
29
31
|
body = node_stream_1.Readable.fromWeb(request.body);
|
|
30
32
|
}
|
|
31
33
|
const stream = await session.stream(request.method, request.url, {
|
|
32
|
-
headers, body, profile: init.profile, proxy: init.proxy, proxyCaFile: init.proxyCaFile,
|
|
34
|
+
headers, body, profile: init.profile, profileSpec: init.profileSpec, httpVersion: init.httpVersion, proxy: init.proxy, proxyCaFile: init.proxyCaFile,
|
|
33
35
|
timeoutMs: init.timeoutMs, maxRedirects: init.maxRedirects,
|
|
34
36
|
allowRedirects: request.redirect === "follow", signal: request.signal,
|
|
35
37
|
});
|
|
@@ -108,6 +110,7 @@ async function fetchWithSession(session, input, init = {}, owned = false) {
|
|
|
108
110
|
/** Fetch-compatible entry point. No persistent cookie jar is created. */
|
|
109
111
|
async function fetch(input, init = {}) {
|
|
110
112
|
const options = { cookies: false, profile: init.profile, proxy: init.proxy,
|
|
113
|
+
profileSpec: init.profileSpec, httpVersion: init.httpVersion, addressPolicy: init.addressPolicy,
|
|
111
114
|
proxyCaFile: init.proxyCaFile, caFile: init.caFile, library: init.library, timeoutMs: init.timeoutMs };
|
|
112
115
|
return fetchWithSession(new session_js_1.Session(options), input, init, true);
|
|
113
116
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { Session } from "./session.js";
|
|
2
|
+
export { ProfileSpec } from "./profiles.js";
|
|
3
|
+
export type { AddressPolicy } from "./profiles.js";
|
|
2
4
|
export { fetch } from "./fetch.js";
|
|
3
5
|
export type { FetchOptions, FetchResponse } from "./fetch.js";
|
|
4
6
|
export type { SessionOptions, RequestOptions, DuplexOptions, Stats } from "./session.js";
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FastlsTimeoutError = exports.FastlsDecodeError = exports.AbortError = exports.FastlsHTTPError = exports.FastlsError = exports.Cookies = exports.Headers = exports.StreamResponse = exports.Response = exports.SSEStream = exports.ServerSentEvent = exports.WebSocketClosed = exports.WebSocket = exports.DuplexExchange = exports.Session = void 0;
|
|
3
|
+
exports.FastlsTimeoutError = exports.FastlsDecodeError = exports.AbortError = exports.FastlsHTTPError = exports.FastlsError = exports.Cookies = exports.Headers = exports.StreamResponse = exports.Response = exports.SSEStream = exports.ServerSentEvent = exports.WebSocketClosed = exports.WebSocket = exports.DuplexExchange = exports.ProfileSpec = exports.Session = void 0;
|
|
4
4
|
var session_js_1 = require("./session.js");
|
|
5
5
|
Object.defineProperty(exports, "Session", { enumerable: true, get: function () { return session_js_1.Session; } });
|
|
6
|
+
var profiles_js_1 = require("./profiles.js");
|
|
7
|
+
Object.defineProperty(exports, "ProfileSpec", { enumerable: true, get: function () { return profiles_js_1.ProfileSpec; } });
|
|
6
8
|
var fetch_js_1 = require("./fetch.js");
|
|
7
9
|
Object.defineProperty(exports, "fetch", { enumerable: true, get: function () { return fetch_js_1.fetch; } });
|
|
8
10
|
var duplex_js_1 = require("./duplex.js");
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import sdk from './index.js';
|
|
2
2
|
export const fetch = sdk.fetch;
|
|
3
|
-
export const { Session, Response, StreamResponse, DuplexExchange, WebSocket, WebSocketClosed, ServerSentEvent, SSEStream, Headers, Cookies, FastlsError, FastlsHTTPError, AbortError, FastlsDecodeError, FastlsTimeoutError } = sdk;
|
|
3
|
+
export const { Session, ProfileSpec, Response, StreamResponse, DuplexExchange, WebSocket, WebSocketClosed, ServerSentEvent, SSEStream, Headers, Cookies, FastlsError, FastlsHTTPError, AbortError, FastlsDecodeError, FastlsTimeoutError } = sdk;
|
package/dist/native.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export interface NativeInfo {
|
|
|
31
31
|
}
|
|
32
32
|
export declare class Native {
|
|
33
33
|
private functions;
|
|
34
|
+
readonly transportOptionsAvailable: boolean;
|
|
34
35
|
readonly notificationsAvailable: boolean;
|
|
35
36
|
readonly websocketAvailable: boolean;
|
|
36
37
|
readonly path: string;
|
|
@@ -38,6 +39,7 @@ export declare class Native {
|
|
|
38
39
|
private constructor();
|
|
39
40
|
call<T = unknown>(name: string, ...args: unknown[]): T;
|
|
40
41
|
start(input: unknown): bigint;
|
|
42
|
+
requireCapabilities(required: readonly string[]): void;
|
|
41
43
|
wsStart(input: unknown): bigint;
|
|
42
44
|
wsSend(handle: bigint, opcode: number, data: Uint8Array): number;
|
|
43
45
|
wsRead(handle: bigint, buffer: Buffer): {
|
package/dist/native.js
CHANGED
|
@@ -62,6 +62,7 @@ function pinLibrary(path) {
|
|
|
62
62
|
}
|
|
63
63
|
class Native {
|
|
64
64
|
functions = {};
|
|
65
|
+
transportOptionsAvailable = false;
|
|
65
66
|
notificationsAvailable;
|
|
66
67
|
websocketAvailable;
|
|
67
68
|
path;
|
|
@@ -103,6 +104,13 @@ class Native {
|
|
|
103
104
|
this.functions.read = lib.func("int fastls_read(uint64_t handle, _Out_ void *buffer, size_t capacity, _Out_ size_t *length)");
|
|
104
105
|
this.functions.write = lib.func("int fastls_write(uint64_t handle, const void *buffer, size_t length, int end)");
|
|
105
106
|
const features = new Set(this.call("features"));
|
|
107
|
+
if (features.has("transport_options_v1")) {
|
|
108
|
+
try {
|
|
109
|
+
this.functions.transport_create_with_options = lib.func("void *fastls_transport_create_with_options(void *json, size_t length)");
|
|
110
|
+
this.transportOptionsAvailable = true;
|
|
111
|
+
}
|
|
112
|
+
catch { /* Optional symbol: old default transport stays loadable. */ }
|
|
113
|
+
}
|
|
106
114
|
if (features.has("transport_context_v1")) {
|
|
107
115
|
this.functions.transport_create = lib.func("void *fastls_transport_create(void)");
|
|
108
116
|
}
|
|
@@ -149,19 +157,30 @@ class Native {
|
|
|
149
157
|
// Starts, sessions and notification batches contain uint64 handles. Catalogs, headers
|
|
150
158
|
// and info metadata use strings and bounded numeric fields; avoid the
|
|
151
159
|
// allocating JS numeric parser on every poll and catalog lookup.
|
|
152
|
-
envelope = (name === "start" || name === "ws_start" || name === "session_create" || name === "session_events" ? parseNativeJSON(json) : JSON.parse(json));
|
|
160
|
+
envelope = (name === "start" || name === "ws_start" || name === "session_create" || name === "transport_create" || name === "transport_create_with_options" || name === "session_events" ? parseNativeJSON(json) : JSON.parse(json));
|
|
153
161
|
}
|
|
154
162
|
finally {
|
|
155
163
|
this.functions.free(pointer);
|
|
156
164
|
}
|
|
157
|
-
if (!envelope?.ok)
|
|
158
|
-
|
|
165
|
+
if (!envelope?.ok) {
|
|
166
|
+
const error = new errors_js_1.FastlsError(envelope?.error ?? "invalid native result");
|
|
167
|
+
error.code = envelope?.error_code;
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
159
170
|
return envelope.result;
|
|
160
171
|
}
|
|
161
172
|
start(input) {
|
|
162
173
|
const raw = encodeNativeJSON(input);
|
|
163
174
|
return asHandle(this.call("start", raw, raw.length));
|
|
164
175
|
}
|
|
176
|
+
requireCapabilities(required) {
|
|
177
|
+
const features = new Set(this.call("features"));
|
|
178
|
+
if (!this.transportOptionsAvailable || required.some(name => !features.has(name))) {
|
|
179
|
+
const error = new errors_js_1.FastlsError("native transport capability is unavailable");
|
|
180
|
+
error.code = "unsupported_capability";
|
|
181
|
+
throw error;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
165
184
|
wsStart(input) {
|
|
166
185
|
if (!this.websocketAvailable)
|
|
167
186
|
throw new errors_js_1.FastlsError("WebSocket requires a newer Fastls native library");
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Trusted immutable session policy. Keys follow the native versioned schema. */
|
|
2
|
+
export interface AddressPolicy {
|
|
3
|
+
readonly allow_schemes?: readonly ("http" | "https")[];
|
|
4
|
+
readonly allow_hosts?: readonly string[];
|
|
5
|
+
readonly allow_ports?: readonly number[];
|
|
6
|
+
readonly allow_cidrs?: readonly string[];
|
|
7
|
+
readonly deny_cidrs?: readonly string[];
|
|
8
|
+
}
|
|
9
|
+
/** Explicit snapshot of a complete schema-v1 profile, validated by the core. */
|
|
10
|
+
export declare class ProfileSpec {
|
|
11
|
+
private readonly snapshot;
|
|
12
|
+
constructor(value: Readonly<Record<string, unknown>>);
|
|
13
|
+
toJSON(): Record<string, unknown>;
|
|
14
|
+
}
|
package/dist/profiles.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProfileSpec = void 0;
|
|
4
|
+
/** Explicit snapshot of a complete schema-v1 profile, validated by the core. */
|
|
5
|
+
class ProfileSpec {
|
|
6
|
+
snapshot;
|
|
7
|
+
constructor(value) {
|
|
8
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
9
|
+
throw new TypeError("ProfileSpec requires an object");
|
|
10
|
+
this.snapshot = JSON.stringify(value);
|
|
11
|
+
if (Buffer.byteLength(this.snapshot) > 256 * 1024)
|
|
12
|
+
throw new RangeError("profileSpec exceeds 256KiB");
|
|
13
|
+
}
|
|
14
|
+
toJSON() { return JSON.parse(this.snapshot); }
|
|
15
|
+
}
|
|
16
|
+
exports.ProfileSpec = ProfileSpec;
|
package/dist/session.d.ts
CHANGED
|
@@ -7,7 +7,10 @@ import { SSEStream, type SSEOptions } from "./sse.js";
|
|
|
7
7
|
import { type QueryParams, type JSONValue, type FormFields, type MultipartFiles } from "./request-options.js";
|
|
8
8
|
import { WebSocket, type WebSocketOptions } from "./websocket.js";
|
|
9
9
|
import { type FetchOptions, type FetchResponse } from "./fetch.js";
|
|
10
|
+
import { ProfileSpec, type AddressPolicy } from "./profiles.js";
|
|
10
11
|
export interface RequestOptions {
|
|
12
|
+
profileSpec?: ProfileSpec;
|
|
13
|
+
httpVersion?: "auto" | "h3";
|
|
11
14
|
/** Undefined inherits the session proxy; null or an empty string connects directly. */
|
|
12
15
|
proxy?: string | null;
|
|
13
16
|
/** Undefined inherits proxy trust; null uses system roots. Only HTTPS proxies use this file. */
|
|
@@ -32,6 +35,9 @@ export interface RequestOptions {
|
|
|
32
35
|
}
|
|
33
36
|
export type DuplexOptions = Omit<RequestOptions, "body" | "duplex" | "json" | "form" | "files">;
|
|
34
37
|
export interface SessionOptions {
|
|
38
|
+
addressPolicy?: AddressPolicy;
|
|
39
|
+
profileSpec?: ProfileSpec;
|
|
40
|
+
httpVersion?: "auto" | "h3";
|
|
35
41
|
/** HTTP/HTTPS CONNECT, socks5 (local DNS), or socks5h (proxy DNS) URL. */
|
|
36
42
|
proxy?: string | null;
|
|
37
43
|
/** Private roots for proxy TLS, independent of the target's caFile. */
|
package/dist/session.js
CHANGED
|
@@ -15,6 +15,7 @@ const notifications_js_1 = require("./notifications.js");
|
|
|
15
15
|
const request_options_js_1 = require("./request-options.js");
|
|
16
16
|
const websocket_js_1 = require("./websocket.js");
|
|
17
17
|
const fetch_js_1 = require("./fetch.js");
|
|
18
|
+
const profiles_js_1 = require("./profiles.js");
|
|
18
19
|
function decoding(decode, maximum) {
|
|
19
20
|
if (typeof decode !== "boolean")
|
|
20
21
|
throw new TypeError("decodeContent must be a boolean");
|
|
@@ -86,7 +87,15 @@ class Session {
|
|
|
86
87
|
const notifications = options.notifications === undefined ? "auto" : options.notifications;
|
|
87
88
|
if (!["auto", "required", "poll"].includes(notifications))
|
|
88
89
|
throw new TypeError("notifications must be auto, required or poll");
|
|
89
|
-
|
|
90
|
+
if (options.profile !== undefined && typeof options.profile !== "string")
|
|
91
|
+
throw new TypeError("profile must be a selector string");
|
|
92
|
+
if (options.profileSpec !== undefined && !(options.profileSpec instanceof profiles_js_1.ProfileSpec))
|
|
93
|
+
throw new TypeError("profileSpec must be a ProfileSpec");
|
|
94
|
+
if (options.profile !== undefined && options.profileSpec !== undefined)
|
|
95
|
+
throw new TypeError("profile and profileSpec are mutually exclusive");
|
|
96
|
+
if (options.httpVersion !== undefined && !["auto", "h3"].includes(options.httpVersion))
|
|
97
|
+
throw new TypeError("httpVersion must be auto or h3");
|
|
98
|
+
this.profile = options.profile ?? (options.profileSpec !== undefined || options.httpVersion === "h3" ? "" : "chrome/156/windows");
|
|
90
99
|
this.timeouts = (0, timeout_js_1.timeoutFields)(options.timeoutMs ?? 30000);
|
|
91
100
|
this.decodeContent = options.decodeContent ?? true;
|
|
92
101
|
this.maxDecodedBytes = options.maxDecodedBytes ?? 256 * 1024 * 1024;
|
|
@@ -104,7 +113,36 @@ class Session {
|
|
|
104
113
|
this.notificationMode = notifications !== "poll" && supported ? "async-events" : "poll";
|
|
105
114
|
if (!this.native.call("features").includes("transport_context_v1"))
|
|
106
115
|
throw new errors_js_1.FastlsError("SDK-owned sessions require the Fastls 0.1.4 native library or newer");
|
|
107
|
-
|
|
116
|
+
const configuration = { schema_version: 1 };
|
|
117
|
+
const required = [];
|
|
118
|
+
if (options.addressPolicy !== undefined) {
|
|
119
|
+
if (!options.addressPolicy || typeof options.addressPolicy !== "object" || Array.isArray(options.addressPolicy))
|
|
120
|
+
throw new TypeError("addressPolicy must be an object");
|
|
121
|
+
configuration.address_policy = options.addressPolicy;
|
|
122
|
+
required.push("transport_address_policy_v1");
|
|
123
|
+
}
|
|
124
|
+
if (options.profileSpec !== undefined) {
|
|
125
|
+
configuration.profile_spec = options.profileSpec.toJSON();
|
|
126
|
+
required.push("profile_spec_v1");
|
|
127
|
+
}
|
|
128
|
+
if (options.httpVersion === "h3") {
|
|
129
|
+
configuration.http_version = "h3";
|
|
130
|
+
required.push("http3_v1");
|
|
131
|
+
}
|
|
132
|
+
if (required.length) {
|
|
133
|
+
this.native.requireCapabilities(required);
|
|
134
|
+
if (options.profile !== undefined)
|
|
135
|
+
configuration.profile = options.profile;
|
|
136
|
+
if (this.proxy && (options.addressPolicy !== undefined || options.httpVersion === "h3")) {
|
|
137
|
+
const error = new errors_js_1.FastlsError("unsupported transport combination");
|
|
138
|
+
error.code = "unsupported_capability";
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
const raw = (0, native_js_1.encodeNativeJSON)(configuration);
|
|
142
|
+
this.handle = (0, native_js_1.asHandle)(this.native.call("transport_create_with_options", raw, raw.length));
|
|
143
|
+
}
|
|
144
|
+
else
|
|
145
|
+
this.handle = (0, native_js_1.asHandle)(this.native.call("transport_create"));
|
|
108
146
|
this.cookies = new cookies_js_1.Cookies(() => this.ensureOpen(), options.cookies !== false);
|
|
109
147
|
}
|
|
110
148
|
ensureOpen() {
|
|
@@ -157,6 +195,8 @@ class Session {
|
|
|
157
195
|
}
|
|
158
196
|
begin(method, url, options, manual = false, completeHeaders = false) {
|
|
159
197
|
this.ensureOpen();
|
|
198
|
+
if ("addressPolicy" in options)
|
|
199
|
+
throw new TypeError("addressPolicy is a Session creation option");
|
|
160
200
|
if (options.signal !== undefined && !(options.signal instanceof AbortSignal)) {
|
|
161
201
|
throw new TypeError("signal must be an AbortSignal");
|
|
162
202
|
}
|
|
@@ -215,9 +255,24 @@ class Session {
|
|
|
215
255
|
trailers[name] = [...values];
|
|
216
256
|
}
|
|
217
257
|
}
|
|
258
|
+
if (options.profileSpec !== undefined && !(options.profileSpec instanceof profiles_js_1.ProfileSpec))
|
|
259
|
+
throw new TypeError("profileSpec must be a ProfileSpec");
|
|
260
|
+
if (options.profileSpec !== undefined && options.profile !== undefined)
|
|
261
|
+
throw new TypeError("profile and profileSpec are mutually exclusive");
|
|
262
|
+
const required = [];
|
|
263
|
+
if (options.profileSpec !== undefined)
|
|
264
|
+
required.push("profile_spec_v1");
|
|
265
|
+
if (options.httpVersion !== undefined) {
|
|
266
|
+
if (!["auto", "h3"].includes(options.httpVersion))
|
|
267
|
+
throw new TypeError("httpVersion must be auto or h3");
|
|
268
|
+
required.push("http3_v1");
|
|
269
|
+
}
|
|
270
|
+
if (required.length)
|
|
271
|
+
this.native.requireCapabilities(required);
|
|
218
272
|
const handle = this.native.start({
|
|
219
273
|
session: this.handle, url, method, headers, trailers, proxy: proxy || undefined, proxy_ca_pem: proxyCaPem,
|
|
220
|
-
profile: options.profile ?? this.profile,
|
|
274
|
+
profile: options.profile ?? (options.profileSpec !== undefined || options.httpVersion === "h3" ? "" : this.profile),
|
|
275
|
+
profile_spec: options.profileSpec?.toJSON(), http_version: options.httpVersion,
|
|
221
276
|
...timeouts, decode_content: decodeContent, max_decoded_bytes: maxDecodedBytes,
|
|
222
277
|
disable_redirect: true,
|
|
223
278
|
ca_pem: this.caPem,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fastls/fastls",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Node.js bindings for the Fastls C ABI",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
"registry": "https://registry.npmjs.org/"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|
|
38
|
-
"@fastls/fastls-win32-x64": "0.
|
|
39
|
-
"@fastls/fastls-linux-x64-glibc": "0.
|
|
40
|
-
"@fastls/fastls-linux-arm64-glibc": "0.
|
|
41
|
-
"@fastls/fastls-darwin-x64": "0.
|
|
42
|
-
"@fastls/fastls-darwin-arm64": "0.
|
|
38
|
+
"@fastls/fastls-win32-x64": "0.11.0",
|
|
39
|
+
"@fastls/fastls-linux-x64-glibc": "0.11.0",
|
|
40
|
+
"@fastls/fastls-linux-arm64-glibc": "0.11.0",
|
|
41
|
+
"@fastls/fastls-darwin-x64": "0.11.0",
|
|
42
|
+
"@fastls/fastls-darwin-arm64": "0.11.0"
|
|
43
43
|
}
|
|
44
44
|
}
|