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