@apifuse/provider-sdk 2.2.0-beta.47 → 2.2.0-beta.49
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/AUTHORING.md +91 -36
- package/CHANGELOG.md +8 -0
- package/README.md +11 -9
- package/SUBMISSION.md +1 -1
- package/bin/apifuse-dev.ts +24 -13
- package/bin/apifuse-migrate-operation-declaration.ts +55 -0
- package/bin/apifuse-pack-smoke.ts +1 -1
- package/bin/apifuse-pack-types.ts +2 -1
- package/bin/apifuse-record.ts +30 -16
- package/bin/apifuse-submit-check.ts +20 -35
- package/dist/cli/commands.d.ts +1 -1
- package/dist/cli/commands.js +11 -0
- package/dist/cli/migrate-operation-declaration.d.ts +59 -0
- package/dist/cli/migrate-operation-declaration.js +1178 -0
- package/dist/cli/templates/provider/README.md.tpl +3 -3
- package/dist/cli/templates/provider/operations/ping.ts.tpl +2 -0
- package/dist/config/loader.d.ts +2 -0
- package/dist/config/loader.js +18 -7
- package/dist/contract-types.d.ts +11 -5
- package/dist/contract.js +21 -10
- package/dist/define.d.ts +25 -22
- package/dist/define.js +49 -75
- package/dist/dev.d.ts +3 -0
- package/dist/dev.js +1 -1
- package/dist/engine.d.ts +78 -0
- package/dist/engine.js +133 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/lint.d.ts +7 -15
- package/dist/lint.js +45 -70
- package/dist/provider.d.ts +3 -1
- package/dist/provider.js +1 -0
- package/dist/runtime/chrome149-header-order.d.ts +58 -0
- package/dist/runtime/chrome149-header-order.js +289 -0
- package/dist/runtime/env.js +12 -0
- package/dist/runtime/executor.d.ts +2 -1
- package/dist/runtime/executor.js +3 -36
- package/dist/runtime/insights.js +2 -2
- package/dist/runtime/otlp.d.ts +71 -2
- package/dist/runtime/otlp.js +397 -16
- package/dist/runtime/resolver-public.d.ts +1 -1
- package/dist/runtime/resolver-public.js +1 -1
- package/dist/runtime/resolver-vendors/capsolver.js +9 -3
- package/dist/runtime/resolver-vendors/twocaptcha.js +1 -0
- package/dist/runtime/resolver.d.ts +12 -0
- package/dist/runtime/resolver.js +45 -11
- package/dist/runtime/stealth.d.ts +13 -4
- package/dist/runtime/stealth.js +362 -85
- package/dist/runtime/trace-config.js +2 -1
- package/dist/runtime/trace.d.ts +5 -0
- package/dist/runtime/trace.js +43 -10
- package/dist/server/self-test.d.ts +1 -3
- package/dist/server/self-test.js +2 -12
- package/dist/server/serve-implementation.d.ts +6 -1
- package/dist/server/serve-implementation.js +55 -40
- package/dist/server/trace-output.d.ts +3 -1
- package/dist/server/trace-output.js +61 -2
- package/dist/stealth/profiles.d.ts +9 -8
- package/dist/stealth/profiles.js +123 -286
- package/dist/types.d.ts +116 -108
- package/package.json +2 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/approval-override.ts.txt +6 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/codemod-syntax.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/connection-precedence.ts.txt +10 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/docs-conflict.ts.txt +8 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-map.ts.txt +5 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-operation.ts.txt +16 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-map.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoist-all.ts.txt +31 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoisted-const.ts.txt +11 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/imported-spread.ts.txt +11 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-map.ts.txt +11 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-cast-tail.ts.txt +21 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-ekitan.ts.txt +11 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-override.ts.txt +14 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/missing-english-locale.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/no-safety.ts.txt +6 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/non-literal.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/redundant-approval.ts.txt +6 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/safety-conflict.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/stream.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/tool-router-spread.ts.txt +15 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/unparseable.ts.txt +4 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/verbatim-template.ts.txt +12 -0
- package/src/cli/commands.ts +13 -0
- package/src/cli/migrate-operation-declaration.ts +1654 -0
- package/src/cli/templates/provider/README.md.tpl +3 -3
- package/src/cli/templates/provider/operations/ping.ts.tpl +2 -0
- package/src/config/loader.ts +31 -6
- package/src/contract-types.ts +11 -5
- package/src/contract.ts +21 -10
- package/src/define.ts +107 -119
- package/src/dev.ts +4 -1
- package/src/engine.ts +279 -0
- package/src/index.ts +13 -5
- package/src/lint.ts +58 -92
- package/src/provider.ts +25 -3
- package/src/runtime/chrome149-header-order.ts +330 -0
- package/src/runtime/env.ts +13 -0
- package/src/runtime/executor.ts +7 -40
- package/src/runtime/insights.ts +2 -2
- package/src/runtime/otlp.ts +467 -21
- package/src/runtime/resolver-public.ts +3 -0
- package/src/runtime/resolver-vendors/capsolver.ts +12 -4
- package/src/runtime/resolver-vendors/twocaptcha.ts +1 -0
- package/src/runtime/resolver.ts +68 -19
- package/src/runtime/stealth.ts +435 -103
- package/src/runtime/trace-config.ts +3 -2
- package/src/runtime/trace.ts +57 -17
- package/src/server/self-test.ts +2 -9
- package/src/server/serve-implementation.ts +89 -72
- package/src/server/trace-output.ts +99 -2
- package/src/stealth/profiles.ts +169 -327
- package/src/types.ts +114 -137
package/src/stealth/profiles.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
|
|
3
|
-
import type { BrowserProfile } from "wreq-js";
|
|
3
|
+
import type { BrowserProfile, EmulationOS } from "wreq-js";
|
|
4
4
|
|
|
5
5
|
import { SDKError } from "../errors.js";
|
|
6
|
-
import type {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
import type {
|
|
7
|
+
StealthBrowser,
|
|
8
|
+
StealthProfile,
|
|
9
|
+
StealthProfileDescriptor,
|
|
10
|
+
StealthProfileSelection,
|
|
11
|
+
StealthOS,
|
|
12
|
+
} from "../types.js";
|
|
13
|
+
|
|
14
|
+
type StealthProfileDefinition = Omit<StealthProfile, "browser" | "os">;
|
|
12
15
|
type WreqProfileApi = Pick<typeof import("wreq-js"), "getEmulationHeaders" | "getProfiles">;
|
|
13
16
|
|
|
14
17
|
const requireModule = createRequire(import.meta.url);
|
|
@@ -19,53 +22,8 @@ function getWreqProfileApi(): WreqProfileApi {
|
|
|
19
22
|
return wreqProfileApi;
|
|
20
23
|
}
|
|
21
24
|
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
":authority",
|
|
25
|
-
":scheme",
|
|
26
|
-
":path",
|
|
27
|
-
"user-agent",
|
|
28
|
-
"accept",
|
|
29
|
-
"accept-encoding",
|
|
30
|
-
"accept-language",
|
|
31
|
-
"cache-control",
|
|
32
|
-
"pragma",
|
|
33
|
-
"cookie",
|
|
34
|
-
"sec-ch-ua",
|
|
35
|
-
"sec-ch-ua-mobile",
|
|
36
|
-
"sec-ch-ua-platform",
|
|
37
|
-
];
|
|
38
|
-
|
|
39
|
-
const FIREFOX_HEADER_ORDER = [
|
|
40
|
-
":method",
|
|
41
|
-
":path",
|
|
42
|
-
":authority",
|
|
43
|
-
":scheme",
|
|
44
|
-
"user-agent",
|
|
45
|
-
"accept",
|
|
46
|
-
"accept-language",
|
|
47
|
-
"accept-encoding",
|
|
48
|
-
"referer",
|
|
49
|
-
"cookie",
|
|
50
|
-
"upgrade-insecure-requests",
|
|
51
|
-
"sec-fetch-dest",
|
|
52
|
-
"sec-fetch-mode",
|
|
53
|
-
"sec-fetch-site",
|
|
54
|
-
"sec-fetch-user",
|
|
55
|
-
];
|
|
56
|
-
|
|
57
|
-
const SAFARI_HEADER_ORDER = [
|
|
58
|
-
":method",
|
|
59
|
-
":scheme",
|
|
60
|
-
":path",
|
|
61
|
-
":authority",
|
|
62
|
-
"accept",
|
|
63
|
-
"user-agent",
|
|
64
|
-
"accept-language",
|
|
65
|
-
"accept-encoding",
|
|
66
|
-
"cookie",
|
|
67
|
-
"upgrade-insecure-requests",
|
|
68
|
-
];
|
|
25
|
+
export const DEFAULT_STEALTH_BROWSER = "chrome" as const;
|
|
26
|
+
export const DEFAULT_STEALTH_OS = "macos" as const;
|
|
69
27
|
|
|
70
28
|
const CHROMIUM_H2_SETTINGS = {
|
|
71
29
|
HEADER_TABLE_SIZE: 65536,
|
|
@@ -95,21 +53,104 @@ const FIREFOX_JA3 =
|
|
|
95
53
|
const SAFARI_JA3 =
|
|
96
54
|
"771,4865-4866-4867-49196-49195-52393-49200-49199-49188-49192-159-158-107-103-57-51-157-156-61-60-53-47-255,0-23-65281-10-11-16-5-13-18-51-45-43-27,29-23-24-25,0";
|
|
97
55
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
56
|
+
const SUPPORTED_STEALTH_PROFILES: readonly StealthProfileDescriptor[] = [
|
|
57
|
+
{ browser: "chrome", os: "windows" },
|
|
58
|
+
{ browser: "chrome", os: "macos" },
|
|
59
|
+
{ browser: "chrome", os: "linux" },
|
|
60
|
+
{ browser: "firefox", os: "windows" },
|
|
61
|
+
{ browser: "firefox", os: "macos" },
|
|
62
|
+
{ browser: "firefox", os: "linux" },
|
|
63
|
+
{ browser: "safari", os: "macos" },
|
|
64
|
+
{ browser: "safari", os: "ios" },
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
const DESKTOP_OSES = new Set<StealthOS>(["windows", "macos", "linux"]);
|
|
68
|
+
|
|
69
|
+
function structuredReplacement(browser: StealthBrowser, os: StealthOS): string {
|
|
70
|
+
return `stealth: { browser: "${browser}", os: "${os}" }`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Internal detector used to keep version-pinned string failures actionable. */
|
|
74
|
+
export function getVersionPinnedStealthReplacement(name: string): string | undefined {
|
|
75
|
+
if (/^(?:chrome|chromium|edge)[-_]\d/i.test(name)) {
|
|
76
|
+
return structuredReplacement("chrome", DEFAULT_STEALTH_OS);
|
|
77
|
+
}
|
|
78
|
+
if (/^firefox[-_]\d/i.test(name)) {
|
|
79
|
+
return structuredReplacement("firefox", DEFAULT_STEALTH_OS);
|
|
80
|
+
}
|
|
81
|
+
if (/^(?:ios[-_]safari|safari[-_](?:ios|ipad))[-_]\d/i.test(name)) {
|
|
82
|
+
return structuredReplacement("safari", "ios");
|
|
83
|
+
}
|
|
84
|
+
if (/^safari[-_]\d/i.test(name)) {
|
|
85
|
+
return structuredReplacement("safari", DEFAULT_STEALTH_OS);
|
|
86
|
+
}
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function rejectStringSelection(name: string): never {
|
|
91
|
+
const replacement = getVersionPinnedStealthReplacement(name);
|
|
92
|
+
if (replacement) {
|
|
93
|
+
throw new SDKError(
|
|
94
|
+
`Stealth profile "${name}" pins a browser version and is not supported. Use ${replacement}.`,
|
|
95
|
+
{ code: "STEALTH_VERSION_PIN_UNSUPPORTED" },
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
throw new SDKError(
|
|
99
|
+
`Stealth profile names are no longer supported: "${name}". Use structured browser/os options.`,
|
|
100
|
+
{ code: "STEALTH_PROFILE_NAME_UNSUPPORTED" },
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function assertSupportedDescriptor(browser: StealthBrowser, os: StealthOS): void {
|
|
105
|
+
const supported =
|
|
106
|
+
(browser === "chrome" && DESKTOP_OSES.has(os)) ||
|
|
107
|
+
(browser === "firefox" && DESKTOP_OSES.has(os)) ||
|
|
108
|
+
(browser === "safari" && (os === "macos" || os === "ios"));
|
|
109
|
+
if (!supported) {
|
|
110
|
+
throw new SDKError(
|
|
111
|
+
`Unsupported stealth browser/OS combination: ${browser}/${os}. ` +
|
|
112
|
+
"Chrome and Firefox support windows, macos, and linux; Safari supports macos and ios.",
|
|
113
|
+
{ code: "STEALTH_PROFILE_UNAVAILABLE" },
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Resolve omitted axes and validate that the resulting pair is supported. */
|
|
119
|
+
export function resolveStealthProfileSelection(
|
|
120
|
+
selection: StealthProfileSelection | undefined,
|
|
121
|
+
base?: StealthProfileDescriptor,
|
|
122
|
+
): StealthProfileDescriptor {
|
|
123
|
+
if (typeof selection === "string") rejectStringSelection(selection);
|
|
124
|
+
if (selection !== undefined && (typeof selection !== "object" || selection === null)) {
|
|
125
|
+
throw new SDKError("Stealth profile selection must use structured browser/os options.");
|
|
126
|
+
}
|
|
127
|
+
const unsafeSelection = selection as
|
|
128
|
+
| (Record<string, unknown> & { browser?: unknown; os?: unknown })
|
|
129
|
+
| undefined;
|
|
130
|
+
if (unsafeSelection && "profile" in unsafeSelection) {
|
|
131
|
+
if (typeof unsafeSelection.profile === "string") rejectStringSelection(unsafeSelection.profile);
|
|
132
|
+
throw new SDKError(
|
|
133
|
+
"stealth.profile is no longer supported. Use stealth.browser and stealth.os.",
|
|
134
|
+
{ code: "STEALTH_PROFILE_NAME_UNSUPPORTED" },
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const browser = unsafeSelection?.browser ?? base?.browser ?? DEFAULT_STEALTH_BROWSER;
|
|
139
|
+
if (browser !== "chrome" && browser !== "firefox" && browser !== "safari") {
|
|
140
|
+
throw new SDKError(`Unsupported stealth browser: ${String(browser)}`);
|
|
141
|
+
}
|
|
142
|
+
const browserChanged =
|
|
143
|
+
base !== undefined && unsafeSelection?.browser !== undefined && browser !== base.browser;
|
|
144
|
+
const os =
|
|
145
|
+
unsafeSelection?.os ?? (browserChanged ? DEFAULT_STEALTH_OS : base?.os) ?? DEFAULT_STEALTH_OS;
|
|
146
|
+
if (os !== "windows" && os !== "macos" && os !== "linux" && os !== "ios") {
|
|
147
|
+
throw new SDKError(`Unsupported stealth OS: ${String(os)}`);
|
|
148
|
+
}
|
|
149
|
+
assertSupportedDescriptor(browser, os);
|
|
150
|
+
return { browser, os } as StealthProfileDescriptor;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Resolve the newest Chromium build exposed by the exactly pinned wreq-js package. */
|
|
113
154
|
function resolveLatestChromiumProfile(): {
|
|
114
155
|
readonly wreqName: BrowserProfile;
|
|
115
156
|
readonly version: string;
|
|
@@ -130,292 +171,93 @@ function resolveLatestChromiumProfile(): {
|
|
|
130
171
|
return { wreqName: newest.name, version: `${newest.version}.0.0.0` };
|
|
131
172
|
}
|
|
132
173
|
|
|
133
|
-
/**
|
|
134
|
-
function
|
|
135
|
-
const
|
|
136
|
-
for (const [name, value] of getEmulationHeaders(latest.wreqName, "macos")) {
|
|
174
|
+
/** Read the identity wreq itself emits so the accessor and transport cannot diverge. */
|
|
175
|
+
function emulationUserAgent(profile: BrowserProfile, os: EmulationOS): string {
|
|
176
|
+
for (const [name, value] of getWreqProfileApi().getEmulationHeaders(profile, os)) {
|
|
137
177
|
if (String(name).toLowerCase() === "user-agent") return String(value);
|
|
138
178
|
}
|
|
139
|
-
throw new SDKError(`wreq-js profile ${
|
|
179
|
+
throw new SDKError(`wreq-js profile ${profile} exposes no user-agent header.`, {
|
|
140
180
|
code: "STEALTH_PROFILE_UNAVAILABLE",
|
|
141
181
|
});
|
|
142
182
|
}
|
|
143
183
|
|
|
144
|
-
function createProfile(
|
|
184
|
+
function createProfile(
|
|
185
|
+
descriptor: StealthProfileDescriptor,
|
|
186
|
+
definition: StealthProfileDefinition,
|
|
187
|
+
): StealthProfile {
|
|
145
188
|
return {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
version: definition.version,
|
|
149
|
-
userAgent: definition.userAgent,
|
|
150
|
-
tlsClientIdentifier: definition.tlsClientIdentifier,
|
|
151
|
-
ja3: definition.ja3,
|
|
152
|
-
ja4: definition.ja4,
|
|
189
|
+
...descriptor,
|
|
190
|
+
...definition,
|
|
153
191
|
h2Settings: definition.h2Settings ? { ...definition.h2Settings } : undefined,
|
|
154
|
-
headerOrder: definition.headerOrder ? [...definition.headerOrder] : undefined,
|
|
155
192
|
};
|
|
156
193
|
}
|
|
157
194
|
|
|
158
|
-
function
|
|
159
|
-
|
|
160
|
-
if (chromeVersion) {
|
|
161
|
-
return chromeVersion;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const identifierVersion = profile.tlsClientIdentifier?.match(/(\d+)(?!.*\d)/)?.[1];
|
|
165
|
-
if (identifierVersion) {
|
|
166
|
-
return identifierVersion;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return profile.version.split(".")[0] ?? profile.version;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function toPlatformHeaderValue(platform: StealthPlatform): string {
|
|
173
|
-
switch (platform) {
|
|
174
|
-
case "macos":
|
|
175
|
-
return '"macOS"';
|
|
176
|
-
case "windows":
|
|
177
|
-
return '"Windows"';
|
|
178
|
-
case "linux":
|
|
179
|
-
return '"Linux"';
|
|
180
|
-
case "android":
|
|
181
|
-
return '"Android"';
|
|
182
|
-
case "ios":
|
|
183
|
-
return '"iOS"';
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export function generateLayer2Headers(profile: StealthProfile): Record<string, string> {
|
|
188
|
-
const headers: Record<string, string> = {
|
|
189
|
-
"Accept-Language": "ko-KR,ko;q=0.9,en-US;q=0.8",
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
const identifier = profile.tlsClientIdentifier?.toLowerCase() ?? "";
|
|
193
|
-
const majorVersion = extractBrowserMajorVersion(profile);
|
|
194
|
-
|
|
195
|
-
if (identifier.startsWith("chrome_") || identifier.startsWith("edge_")) {
|
|
196
|
-
const isEdge = identifier.startsWith("edge_") || /\bEdg\//.test(profile.userAgent);
|
|
197
|
-
headers["Sec-Ch-Ua"] = isEdge
|
|
198
|
-
? `"Chromium";v="${majorVersion}", "Microsoft Edge";v="${majorVersion}", "Not)A;Brand";v="99"`
|
|
199
|
-
: `"Chromium";v="${majorVersion}", "Google Chrome";v="${majorVersion}", "Not)A;Brand";v="99"`;
|
|
200
|
-
headers["Sec-Ch-Ua-Platform"] = toPlatformHeaderValue(profile.platform);
|
|
201
|
-
headers["Sec-Ch-Ua-Mobile"] =
|
|
202
|
-
profile.platform === "android" || profile.platform === "ios" ? "?1" : "?0";
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
return headers;
|
|
195
|
+
function profileKey(descriptor: StealthProfileDescriptor): string {
|
|
196
|
+
return `${descriptor.browser}:${descriptor.os}`;
|
|
206
197
|
}
|
|
207
198
|
|
|
208
|
-
|
|
209
|
-
"firefox-desktop": "firefox-147",
|
|
210
|
-
"safari-desktop": "safari-17",
|
|
211
|
-
"safari-mobile": "ios-safari-26",
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
const PUBLIC_STEALTH_PROFILE_NAMES = [
|
|
215
|
-
"chrome-desktop",
|
|
216
|
-
"firefox-desktop",
|
|
217
|
-
"safari-desktop",
|
|
218
|
-
"safari-mobile",
|
|
219
|
-
"generic-desktop",
|
|
220
|
-
"generic-mobile",
|
|
221
|
-
] as const;
|
|
222
|
-
|
|
223
|
-
const PUBLIC_STEALTH_PROFILE_NAME_SET = new Set<string>(PUBLIC_STEALTH_PROFILE_NAMES);
|
|
224
|
-
|
|
225
|
-
const STATIC_STEALTH_PROFILES: Record<string, StealthProfile> = {
|
|
226
|
-
"chrome-146": createProfile("chrome-146", {
|
|
227
|
-
platform: "macos",
|
|
228
|
-
version: "146.0.0.0",
|
|
229
|
-
userAgent:
|
|
230
|
-
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
|
|
231
|
-
tlsClientIdentifier: "chrome_146",
|
|
232
|
-
ja3: CHROMIUM_JA3,
|
|
233
|
-
h2Settings: CHROMIUM_H2_SETTINGS,
|
|
234
|
-
headerOrder: CHROMIUM_HEADER_ORDER,
|
|
235
|
-
}),
|
|
236
|
-
"firefox-147": createProfile("firefox-147", {
|
|
237
|
-
platform: "macos",
|
|
238
|
-
version: "147.0",
|
|
239
|
-
userAgent:
|
|
240
|
-
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:147.0) Gecko/20100101 Firefox/147.0",
|
|
241
|
-
tlsClientIdentifier: "firefox_147",
|
|
242
|
-
ja3: FIREFOX_JA3,
|
|
243
|
-
h2Settings: FIREFOX_H2_SETTINGS,
|
|
244
|
-
headerOrder: FIREFOX_HEADER_ORDER,
|
|
245
|
-
}),
|
|
246
|
-
"firefox-135": createProfile("firefox-135", {
|
|
247
|
-
platform: "macos",
|
|
248
|
-
version: "135.0",
|
|
249
|
-
userAgent:
|
|
250
|
-
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:135.0) Gecko/20100101 Firefox/135.0",
|
|
251
|
-
tlsClientIdentifier: "firefox_135",
|
|
252
|
-
ja3: FIREFOX_JA3,
|
|
253
|
-
h2Settings: FIREFOX_H2_SETTINGS,
|
|
254
|
-
headerOrder: FIREFOX_HEADER_ORDER,
|
|
255
|
-
}),
|
|
256
|
-
"firefox-133": createProfile("firefox-133", {
|
|
257
|
-
platform: "macos",
|
|
258
|
-
version: "133.0",
|
|
259
|
-
userAgent:
|
|
260
|
-
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:133.0) Gecko/20100101 Firefox/133.0",
|
|
261
|
-
tlsClientIdentifier: "firefox_133",
|
|
262
|
-
ja3: FIREFOX_JA3,
|
|
263
|
-
h2Settings: FIREFOX_H2_SETTINGS,
|
|
264
|
-
headerOrder: FIREFOX_HEADER_ORDER,
|
|
265
|
-
}),
|
|
266
|
-
"firefox-132": createProfile("firefox-132", {
|
|
267
|
-
platform: "macos",
|
|
268
|
-
version: "133.0",
|
|
269
|
-
userAgent:
|
|
270
|
-
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:133.0) Gecko/20100101 Firefox/133.0",
|
|
271
|
-
tlsClientIdentifier: "firefox_132",
|
|
272
|
-
ja3: FIREFOX_JA3,
|
|
273
|
-
h2Settings: FIREFOX_H2_SETTINGS,
|
|
274
|
-
headerOrder: FIREFOX_HEADER_ORDER,
|
|
275
|
-
}),
|
|
276
|
-
"safari-16": createProfile("safari-16", {
|
|
277
|
-
platform: "macos",
|
|
278
|
-
version: "16.0",
|
|
279
|
-
userAgent:
|
|
280
|
-
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15",
|
|
281
|
-
tlsClientIdentifier: "safari_16_0",
|
|
282
|
-
ja3: SAFARI_JA3,
|
|
283
|
-
h2Settings: SAFARI_H2_SETTINGS,
|
|
284
|
-
headerOrder: SAFARI_HEADER_ORDER,
|
|
285
|
-
}),
|
|
286
|
-
"safari-17": createProfile("safari-17", {
|
|
287
|
-
platform: "macos",
|
|
288
|
-
version: "17.0",
|
|
289
|
-
userAgent:
|
|
290
|
-
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15",
|
|
291
|
-
tlsClientIdentifier: "safari_17_0",
|
|
292
|
-
ja3: SAFARI_JA3,
|
|
293
|
-
h2Settings: SAFARI_H2_SETTINGS,
|
|
294
|
-
headerOrder: SAFARI_HEADER_ORDER,
|
|
295
|
-
}),
|
|
296
|
-
"safari-15": createProfile("safari-15", {
|
|
297
|
-
platform: "macos",
|
|
298
|
-
version: "15.6.1",
|
|
299
|
-
userAgent:
|
|
300
|
-
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.6.1 Safari/605.1.15",
|
|
301
|
-
tlsClientIdentifier: "safari_15_6_1",
|
|
302
|
-
ja3: SAFARI_JA3,
|
|
303
|
-
h2Settings: SAFARI_H2_SETTINGS,
|
|
304
|
-
headerOrder: SAFARI_HEADER_ORDER,
|
|
305
|
-
}),
|
|
306
|
-
"ios-safari-26": createProfile("ios-safari-26", {
|
|
307
|
-
platform: "ios",
|
|
308
|
-
version: "26.0",
|
|
309
|
-
userAgent:
|
|
310
|
-
"Mozilla/5.0 (iPhone; CPU iPhone OS 26_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Mobile/15E148 Safari/604.1",
|
|
311
|
-
tlsClientIdentifier: "safari_ios_26_0",
|
|
312
|
-
ja3: SAFARI_JA3,
|
|
313
|
-
h2Settings: SAFARI_H2_SETTINGS,
|
|
314
|
-
headerOrder: SAFARI_HEADER_ORDER,
|
|
315
|
-
}),
|
|
316
|
-
"ios-safari-18": createProfile("ios-safari-18", {
|
|
317
|
-
platform: "ios",
|
|
318
|
-
version: "18.1.1",
|
|
319
|
-
userAgent:
|
|
320
|
-
"Mozilla/5.0 (iPhone; CPU iPhone OS 18_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1.1 Mobile/15E148 Safari/604.1",
|
|
321
|
-
tlsClientIdentifier: "safari_ios_18_0",
|
|
322
|
-
ja3: SAFARI_JA3,
|
|
323
|
-
h2Settings: SAFARI_H2_SETTINGS,
|
|
324
|
-
headerOrder: SAFARI_HEADER_ORDER,
|
|
325
|
-
}),
|
|
326
|
-
"ios-safari-17": createProfile("ios-safari-17", {
|
|
327
|
-
platform: "ios",
|
|
328
|
-
version: "17.2",
|
|
329
|
-
userAgent:
|
|
330
|
-
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1",
|
|
331
|
-
tlsClientIdentifier: "safari_ios_17_0",
|
|
332
|
-
ja3: SAFARI_JA3,
|
|
333
|
-
h2Settings: SAFARI_H2_SETTINGS,
|
|
334
|
-
headerOrder: SAFARI_HEADER_ORDER,
|
|
335
|
-
}),
|
|
336
|
-
"generic-mobile": createProfile("generic-mobile", {
|
|
337
|
-
platform: "ios",
|
|
338
|
-
version: "26.0",
|
|
339
|
-
userAgent:
|
|
340
|
-
"Mozilla/5.0 (iPhone; CPU iPhone OS 26_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Mobile/15E148 Safari/604.1",
|
|
341
|
-
tlsClientIdentifier: "safari_ios_26_0",
|
|
342
|
-
ja3: SAFARI_JA3,
|
|
343
|
-
h2Settings: SAFARI_H2_SETTINGS,
|
|
344
|
-
headerOrder: SAFARI_HEADER_ORDER,
|
|
345
|
-
}),
|
|
346
|
-
};
|
|
347
|
-
|
|
348
|
-
type StealthProfileCatalog = {
|
|
349
|
-
aliases: Record<string, string>;
|
|
350
|
-
profiles: Record<string, StealthProfile>;
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
let stealthProfileCatalog: StealthProfileCatalog | undefined;
|
|
199
|
+
let stealthProfileCatalog: Map<string, StealthProfile> | undefined;
|
|
354
200
|
|
|
355
|
-
function getStealthProfileCatalog():
|
|
201
|
+
function getStealthProfileCatalog(): Map<string, StealthProfile> {
|
|
356
202
|
if (stealthProfileCatalog) return stealthProfileCatalog;
|
|
357
203
|
|
|
358
|
-
const
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
"chrome-desktop": currentName,
|
|
372
|
-
...STATIC_STEALTH_PROFILE_ALIASES,
|
|
204
|
+
const latestChrome = resolveLatestChromiumProfile();
|
|
205
|
+
const definitions: Record<StealthBrowser, Omit<StealthProfileDefinition, "userAgent">> = {
|
|
206
|
+
chrome: {
|
|
207
|
+
version: latestChrome.version,
|
|
208
|
+
tlsClientIdentifier: latestChrome.wreqName,
|
|
209
|
+
ja3: CHROMIUM_JA3,
|
|
210
|
+
h2Settings: CHROMIUM_H2_SETTINGS,
|
|
211
|
+
},
|
|
212
|
+
firefox: {
|
|
213
|
+
version: "147.0",
|
|
214
|
+
tlsClientIdentifier: "firefox_147",
|
|
215
|
+
ja3: FIREFOX_JA3,
|
|
216
|
+
h2Settings: FIREFOX_H2_SETTINGS,
|
|
373
217
|
},
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
218
|
+
safari: {
|
|
219
|
+
version: "17.0",
|
|
220
|
+
tlsClientIdentifier: "safari_17.0",
|
|
221
|
+
ja3: SAFARI_JA3,
|
|
222
|
+
h2Settings: SAFARI_H2_SETTINGS,
|
|
378
223
|
},
|
|
379
224
|
};
|
|
225
|
+
|
|
226
|
+
stealthProfileCatalog = new Map();
|
|
227
|
+
for (const descriptor of SUPPORTED_STEALTH_PROFILES) {
|
|
228
|
+
const isMobileSafari = descriptor.browser === "safari" && descriptor.os === "ios";
|
|
229
|
+
const definition = isMobileSafari
|
|
230
|
+
? {
|
|
231
|
+
version: "26.0",
|
|
232
|
+
tlsClientIdentifier: "safari_ios_26" as BrowserProfile,
|
|
233
|
+
ja3: SAFARI_JA3,
|
|
234
|
+
h2Settings: SAFARI_H2_SETTINGS,
|
|
235
|
+
}
|
|
236
|
+
: definitions[descriptor.browser];
|
|
237
|
+
const wreqName = definition.tlsClientIdentifier as BrowserProfile;
|
|
238
|
+
stealthProfileCatalog.set(
|
|
239
|
+
profileKey(descriptor),
|
|
240
|
+
createProfile(descriptor, {
|
|
241
|
+
...definition,
|
|
242
|
+
userAgent: emulationUserAgent(wreqName, descriptor.os),
|
|
243
|
+
}),
|
|
244
|
+
);
|
|
245
|
+
}
|
|
380
246
|
return stealthProfileCatalog;
|
|
381
247
|
}
|
|
382
248
|
|
|
383
|
-
export function getStealthProfile(
|
|
384
|
-
const
|
|
385
|
-
const
|
|
386
|
-
const profile = catalog.profiles[canonicalName];
|
|
387
|
-
|
|
249
|
+
export function getStealthProfile(selection: StealthProfileSelection = {}): StealthProfile {
|
|
250
|
+
const descriptor = resolveStealthProfileSelection(selection);
|
|
251
|
+
const profile = getStealthProfileCatalog().get(profileKey(descriptor));
|
|
388
252
|
if (!profile) {
|
|
389
|
-
throw new SDKError(`Unknown stealth profile: ${
|
|
253
|
+
throw new SDKError(`Unknown stealth profile: ${descriptor.browser}/${descriptor.os}`);
|
|
390
254
|
}
|
|
391
|
-
|
|
392
255
|
return {
|
|
393
256
|
...profile,
|
|
394
257
|
h2Settings: profile.h2Settings ? { ...profile.h2Settings } : undefined,
|
|
395
|
-
headerOrder: profile.headerOrder ? [...profile.headerOrder] : undefined,
|
|
396
258
|
};
|
|
397
259
|
}
|
|
398
260
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
if (PUBLIC_STEALTH_PROFILE_NAME_SET.has(name)) return undefined;
|
|
402
|
-
if (/^(?:chrome|chromium|edge)[-_]\d/i.test(name)) {
|
|
403
|
-
return "chrome-desktop";
|
|
404
|
-
}
|
|
405
|
-
if (/^firefox[-_]\d/i.test(name)) return "firefox-desktop";
|
|
406
|
-
if (/^(?:ios[-_]safari|safari[-_](?:ios|ipad))[-_]\d/i.test(name)) {
|
|
407
|
-
return "safari-mobile";
|
|
408
|
-
}
|
|
409
|
-
if (/^safari[-_]\d/i.test(name)) return "safari-desktop";
|
|
410
|
-
return undefined;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
/** Internal compatibility catalog used by transport-parity tests. */
|
|
414
|
-
export function listRegisteredStealthProfiles(): string[] {
|
|
415
|
-
const catalog = getStealthProfileCatalog();
|
|
416
|
-
return [...Object.keys(catalog.profiles), ...Object.keys(catalog.aliases)];
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
export function listStealthProfiles(): string[] {
|
|
420
|
-
return [...PUBLIC_STEALTH_PROFILE_NAMES];
|
|
261
|
+
export function listStealthProfiles(): StealthProfileDescriptor[] {
|
|
262
|
+
return SUPPORTED_STEALTH_PROFILES.map((profile) => ({ ...profile }));
|
|
421
263
|
}
|