@apifuse/provider-sdk 2.2.0-beta.7 → 2.2.0-beta.70

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 (478) hide show
  1. package/AUTHORING.md +943 -51
  2. package/CHANGELOG.md +273 -1
  3. package/LICENSE +21 -0
  4. package/README.md +117 -29
  5. package/SUBMISSION.md +3 -2
  6. package/bin/apifuse-check.ts +293 -13
  7. package/bin/apifuse-dev.ts +42 -19
  8. package/bin/apifuse-migrate-deployment.ts +200 -0
  9. package/bin/apifuse-migrate-operation-declaration.ts +55 -0
  10. package/bin/apifuse-migrate-shape.ts +202 -0
  11. package/bin/apifuse-pack-check.ts +19 -6
  12. package/bin/apifuse-pack-smoke.ts +57 -2
  13. package/bin/apifuse-pack-types.ts +736 -38
  14. package/bin/apifuse-perf.ts +59 -23
  15. package/bin/apifuse-record.ts +923 -94
  16. package/bin/apifuse-submit-check.ts +2313 -281
  17. package/bin/apifuse-test.ts +3 -1
  18. package/bin/submit-check-delimited-text.ts +50 -0
  19. package/dist/auth-turn/index.d.ts +3 -3
  20. package/dist/auth-turn/index.js +1 -1
  21. package/dist/auth.d.ts +14 -0
  22. package/dist/auth.js +67 -0
  23. package/dist/ceremonies/index.d.ts +16 -0
  24. package/dist/ceremonies/index.js +141 -36
  25. package/dist/cli/commands.d.ts +1 -1
  26. package/dist/cli/commands.js +30 -0
  27. package/dist/cli/create.d.ts +1 -1
  28. package/dist/cli/create.js +8 -2
  29. package/dist/cli/deployment-intent.d.ts +178 -0
  30. package/dist/cli/deployment-intent.js +277 -0
  31. package/dist/cli/local-connection.d.ts +111 -0
  32. package/dist/cli/local-connection.js +151 -0
  33. package/dist/cli/migrate-deployment-intent.d.ts +132 -0
  34. package/dist/cli/migrate-deployment-intent.js +1552 -0
  35. package/dist/cli/migrate-operation-declaration.d.ts +70 -0
  36. package/dist/cli/migrate-operation-declaration.js +2206 -0
  37. package/dist/cli/migrate-operation-shape.d.ts +44 -0
  38. package/dist/cli/migrate-operation-shape.js +113 -0
  39. package/dist/cli/migrate-provider-shape.d.ts +56 -0
  40. package/dist/cli/migrate-provider-shape.js +580 -0
  41. package/dist/cli/resolver-runtime.d.ts +21 -0
  42. package/dist/cli/resolver-runtime.js +31 -0
  43. package/dist/cli/templates/provider/.agents/skills/health-checks-and-fail-closed/SKILL.md.tpl +141 -23
  44. package/dist/cli/templates/provider/Dockerfile.tpl +1 -1
  45. package/dist/cli/templates/provider/README.md.tpl +41 -19
  46. package/dist/cli/templates/provider/index.ts.tpl +6 -3
  47. package/dist/cli/templates/provider/operations/ping.ts.tpl +4 -1
  48. package/dist/cli/templates/provider/provider.json.tpl +6 -0
  49. package/dist/config/loader.d.ts +202 -16
  50. package/dist/config/loader.js +491 -141
  51. package/dist/contract-serialization.js +4 -8
  52. package/dist/contract-types.d.ts +12 -5
  53. package/dist/contract.js +24 -10
  54. package/dist/declaration-validation.d.ts +34 -0
  55. package/dist/declaration-validation.js +305 -0
  56. package/dist/define.d.ts +71 -29
  57. package/dist/define.js +807 -69
  58. package/dist/dev.d.ts +5 -0
  59. package/dist/dev.js +8 -1
  60. package/dist/engine.d.ts +129 -0
  61. package/dist/engine.js +209 -0
  62. package/dist/error-observability.d.ts +7 -0
  63. package/dist/error-observability.js +61 -0
  64. package/dist/error-resolution.d.ts +18 -0
  65. package/dist/error-resolution.js +243 -0
  66. package/dist/errors.d.ts +74 -0
  67. package/dist/errors.js +99 -0
  68. package/dist/fixture-sanitization.d.ts +28 -0
  69. package/dist/fixture-sanitization.js +371 -0
  70. package/dist/handle-meta.d.ts +90 -0
  71. package/dist/handle-meta.js +73 -0
  72. package/dist/handle.d.ts +226 -0
  73. package/dist/handle.js +345 -0
  74. package/dist/health-scenario.d.ts +1901 -0
  75. package/dist/health-scenario.js +653 -0
  76. package/dist/i18n/catalog.js +21 -1
  77. package/dist/i18n/error-messages.d.ts +86 -0
  78. package/dist/i18n/error-messages.js +192 -0
  79. package/dist/i18n/index.d.ts +1 -0
  80. package/dist/i18n/index.js +1 -0
  81. package/dist/i18n/keys.d.ts +12 -0
  82. package/dist/i18n/keys.js +76 -5
  83. package/dist/i18n/operation-locale-namespace.d.ts +2 -0
  84. package/dist/i18n/operation-locale-namespace.js +7 -0
  85. package/dist/index.d.ts +40 -15
  86. package/dist/index.js +29 -11
  87. package/dist/lint.d.ts +43 -11
  88. package/dist/lint.js +2512 -177
  89. package/dist/native-address.d.ts +43 -0
  90. package/dist/native-address.js +281 -0
  91. package/dist/native-egress-policy.d.ts +31 -0
  92. package/dist/native-egress-policy.js +288 -0
  93. package/dist/observability.d.ts +5 -2
  94. package/dist/observability.js +48 -1
  95. package/dist/provider.d.ts +18 -8
  96. package/dist/provider.js +11 -6
  97. package/dist/runtime/auth-flow.d.ts +6 -1
  98. package/dist/runtime/auth-flow.js +8 -0
  99. package/dist/runtime/bounded-expiring-map.d.ts +21 -0
  100. package/dist/runtime/bounded-expiring-map.js +64 -0
  101. package/dist/runtime/browser-telemetry-binding.d.ts +5 -0
  102. package/dist/runtime/browser-telemetry-binding.js +83 -0
  103. package/dist/runtime/browser-telemetry.d.ts +76 -0
  104. package/dist/runtime/browser-telemetry.js +165 -0
  105. package/dist/runtime/browser.d.ts +4 -0
  106. package/dist/runtime/browser.js +688 -83
  107. package/dist/runtime/cache-telemetry.d.ts +71 -0
  108. package/dist/runtime/cache-telemetry.js +177 -0
  109. package/dist/runtime/cache.d.ts +3 -0
  110. package/dist/runtime/cache.js +245 -23
  111. package/dist/runtime/capability-response.d.ts +3 -0
  112. package/dist/runtime/capability-response.js +56 -0
  113. package/dist/runtime/capability-telemetry.d.ts +46 -0
  114. package/dist/runtime/capability-telemetry.js +68 -0
  115. package/dist/runtime/chrome149-header-order.d.ts +58 -0
  116. package/dist/runtime/chrome149-header-order.js +289 -0
  117. package/dist/runtime/diagnostic-env-values.d.ts +5 -0
  118. package/dist/runtime/diagnostic-env-values.js +57 -0
  119. package/dist/runtime/diagnostic-env.d.ts +14 -0
  120. package/dist/runtime/diagnostic-env.js +44 -0
  121. package/dist/runtime/diagnostic-redactor.d.ts +54 -0
  122. package/dist/runtime/diagnostic-redactor.js +571 -0
  123. package/dist/runtime/egress-lease.d.ts +65 -0
  124. package/dist/runtime/egress-lease.js +236 -0
  125. package/dist/runtime/engine-mode.d.ts +74 -0
  126. package/dist/runtime/engine-mode.js +152 -0
  127. package/dist/runtime/env.js +14 -1
  128. package/dist/runtime/executor.d.ts +3 -2
  129. package/dist/runtime/executor.js +23 -26
  130. package/dist/runtime/handle-wordlist.d.ts +43 -0
  131. package/dist/runtime/handle-wordlist.js +256 -0
  132. package/dist/runtime/handle.d.ts +71 -0
  133. package/dist/runtime/handle.js +908 -0
  134. package/dist/runtime/http-telemetry-binding.d.ts +10 -0
  135. package/dist/runtime/http-telemetry-binding.js +152 -0
  136. package/dist/runtime/http-telemetry-guard.d.ts +16 -0
  137. package/dist/runtime/http-telemetry-guard.js +202 -0
  138. package/dist/runtime/http-telemetry.d.ts +104 -0
  139. package/dist/runtime/http-telemetry.js +190 -0
  140. package/dist/runtime/http.d.ts +34 -0
  141. package/dist/runtime/http.js +680 -121
  142. package/dist/runtime/insights.js +2 -2
  143. package/dist/runtime/instrumentation.d.ts +2 -2
  144. package/dist/runtime/instrumentation.js +462 -19
  145. package/dist/runtime/native-network-errors.d.ts +33 -0
  146. package/dist/runtime/native-network-errors.js +69 -0
  147. package/dist/runtime/native-network.d.ts +105 -0
  148. package/dist/runtime/native-network.js +1433 -0
  149. package/dist/runtime/native-telemetry.d.ts +142 -0
  150. package/dist/runtime/native-telemetry.js +231 -0
  151. package/dist/runtime/ocr-telemetry.d.ts +82 -0
  152. package/dist/runtime/ocr-telemetry.js +192 -0
  153. package/dist/runtime/ocr.d.ts +29 -0
  154. package/dist/runtime/ocr.js +468 -0
  155. package/dist/runtime/otlp.d.ts +71 -2
  156. package/dist/runtime/otlp.js +398 -16
  157. package/dist/runtime/provider.d.ts +7 -0
  158. package/dist/runtime/provider.js +14 -0
  159. package/dist/runtime/proxy-errors.js +6 -2
  160. package/dist/runtime/proxy-nodemaven.d.ts +56 -0
  161. package/dist/runtime/proxy-nodemaven.js +147 -0
  162. package/dist/runtime/proxy-retry-policy.d.ts +4 -1
  163. package/dist/runtime/proxy-retry-policy.js +11 -2
  164. package/dist/runtime/proxy-telemetry.d.ts +133 -3
  165. package/dist/runtime/proxy-telemetry.js +218 -70
  166. package/dist/runtime/redirect-hop-headers.d.ts +19 -0
  167. package/dist/runtime/redirect-hop-headers.js +58 -0
  168. package/dist/runtime/redirects.d.ts +61 -0
  169. package/dist/runtime/redirects.js +149 -0
  170. package/dist/runtime/redis.d.ts +1 -1
  171. package/dist/runtime/redis.js +4 -2
  172. package/dist/runtime/request-options.d.ts +75 -1
  173. package/dist/runtime/request-options.js +588 -0
  174. package/dist/runtime/request-telemetry.d.ts +70 -0
  175. package/dist/runtime/request-telemetry.js +229 -0
  176. package/dist/runtime/resolver-config.d.ts +13 -0
  177. package/dist/runtime/resolver-config.js +14 -0
  178. package/dist/runtime/resolver-public.d.ts +3 -0
  179. package/dist/runtime/resolver-public.js +1 -0
  180. package/dist/runtime/resolver-runtime-options.d.ts +14 -0
  181. package/dist/runtime/resolver-runtime-options.js +33 -0
  182. package/dist/runtime/resolver-shared.d.ts +24 -0
  183. package/dist/runtime/resolver-shared.js +69 -0
  184. package/dist/runtime/resolver-span-attributes.d.ts +34 -0
  185. package/dist/runtime/resolver-span-attributes.js +93 -0
  186. package/dist/runtime/resolver-telemetry.d.ts +135 -0
  187. package/dist/runtime/resolver-telemetry.js +204 -0
  188. package/dist/runtime/resolver-usage.d.ts +32 -0
  189. package/dist/runtime/resolver-usage.js +54 -0
  190. package/dist/runtime/resolver-vendors/bindings.d.ts +53 -0
  191. package/dist/runtime/resolver-vendors/bindings.js +45 -0
  192. package/dist/runtime/resolver-vendors/browser.d.ts +24 -0
  193. package/dist/runtime/resolver-vendors/browser.js +423 -0
  194. package/dist/runtime/resolver-vendors/capsolver.d.ts +22 -0
  195. package/dist/runtime/resolver-vendors/capsolver.js +544 -0
  196. package/dist/runtime/resolver-vendors/hosts.d.ts +23 -0
  197. package/dist/runtime/resolver-vendors/hosts.js +68 -0
  198. package/dist/runtime/resolver-vendors/hypersolutions.d.ts +27 -0
  199. package/dist/runtime/resolver-vendors/hypersolutions.js +369 -0
  200. package/dist/runtime/resolver-vendors/twocaptcha.d.ts +24 -0
  201. package/dist/runtime/resolver-vendors/twocaptcha.js +425 -0
  202. package/dist/runtime/resolver-vendors/types.d.ts +125 -0
  203. package/dist/runtime/resolver-vendors/types.js +106 -0
  204. package/dist/runtime/resolver.d.ts +79 -0
  205. package/dist/runtime/resolver.js +1094 -0
  206. package/dist/runtime/state-telemetry.d.ts +79 -0
  207. package/dist/runtime/state-telemetry.js +194 -0
  208. package/dist/runtime/state.d.ts +10 -1
  209. package/dist/runtime/state.js +322 -82
  210. package/dist/runtime/stealth-akamai-sbsd.d.ts +54 -0
  211. package/dist/runtime/stealth-akamai-sbsd.js +142 -0
  212. package/dist/runtime/stealth-cookies.d.ts +24 -0
  213. package/dist/runtime/stealth-cookies.js +131 -0
  214. package/dist/runtime/stealth-owned-headers.d.ts +39 -0
  215. package/dist/runtime/stealth-owned-headers.js +57 -0
  216. package/dist/runtime/stealth-telemetry.d.ts +92 -0
  217. package/dist/runtime/stealth-telemetry.js +179 -0
  218. package/dist/runtime/stealth.d.ts +45 -6
  219. package/dist/runtime/stealth.js +1775 -320
  220. package/dist/runtime/stt-telemetry.d.ts +77 -0
  221. package/dist/runtime/stt-telemetry.js +176 -0
  222. package/dist/runtime/stt.js +18 -19
  223. package/dist/runtime/timeout.d.ts +5 -0
  224. package/dist/runtime/timeout.js +12 -0
  225. package/dist/runtime/trace-config.d.ts +12 -0
  226. package/dist/runtime/trace-config.js +62 -0
  227. package/dist/runtime/trace.d.ts +17 -0
  228. package/dist/runtime/trace.js +176 -25
  229. package/dist/runtime-boundary-lint.d.ts +137 -0
  230. package/dist/runtime-boundary-lint.js +590 -0
  231. package/dist/schema.d.ts +20 -0
  232. package/dist/schema.js +72 -2
  233. package/dist/serve.d.ts +1 -1
  234. package/dist/serve.js +1 -1
  235. package/dist/server/error-observability.d.ts +1 -0
  236. package/dist/server/error-observability.js +1 -0
  237. package/dist/server/error-stack-frames.d.ts +35 -0
  238. package/dist/server/error-stack-frames.js +219 -0
  239. package/dist/server/index.d.ts +21 -2
  240. package/dist/server/index.js +11 -2
  241. package/dist/server/runtime-diagnostics.d.ts +165 -0
  242. package/dist/server/runtime-diagnostics.js +360 -0
  243. package/dist/server/sdk-version.d.ts +3 -0
  244. package/dist/server/sdk-version.js +19 -0
  245. package/dist/server/self-test-input-tokens.d.ts +2 -1
  246. package/dist/server/self-test-input-tokens.js +18 -14
  247. package/dist/server/self-test-redaction.js +8 -33
  248. package/dist/server/self-test.d.ts +18 -3
  249. package/dist/server/self-test.js +139 -76
  250. package/dist/server/sensitive-values.d.ts +26 -0
  251. package/dist/server/sensitive-values.js +137 -0
  252. package/dist/server/serve-implementation.d.ts +285 -0
  253. package/dist/server/serve-implementation.js +3172 -0
  254. package/dist/server/serve.d.ts +1 -75
  255. package/dist/server/serve.js +1 -1170
  256. package/dist/server/state-backend-report.d.ts +70 -0
  257. package/dist/server/state-backend-report.js +113 -0
  258. package/dist/server/trace-output.d.ts +7 -0
  259. package/dist/server/trace-output.js +111 -0
  260. package/dist/server/types.d.ts +37 -5
  261. package/dist/server/types.js +34 -1
  262. package/dist/stateful/errors.d.ts +19 -0
  263. package/dist/stateful/errors.js +24 -0
  264. package/dist/stateful/http-provider-event-emitter.d.ts +40 -0
  265. package/dist/stateful/http-provider-event-emitter.js +237 -0
  266. package/dist/stateful/http-session-owner-registry.d.ts +44 -0
  267. package/dist/stateful/http-session-owner-registry.js +210 -0
  268. package/dist/stateful/index.d.ts +18 -0
  269. package/dist/stateful/index.js +18 -0
  270. package/dist/stateful/provider-event-delivery-failures.d.ts +32 -0
  271. package/dist/stateful/provider-event-delivery-failures.js +43 -0
  272. package/dist/stateful/provider-event-pipeline-metrics.d.ts +46 -0
  273. package/dist/stateful/provider-event-pipeline-metrics.js +48 -0
  274. package/dist/stateful/provider-event-pipeline.d.ts +50 -0
  275. package/dist/stateful/provider-event-pipeline.js +1 -0
  276. package/dist/stateful/provider-events.d.ts +101 -0
  277. package/dist/stateful/provider-events.js +289 -0
  278. package/dist/stateful/session-key.d.ts +15 -0
  279. package/dist/stateful/session-key.js +86 -0
  280. package/dist/stateful/stateful-provider-adapter-context.d.ts +5 -0
  281. package/dist/stateful/stateful-provider-adapter-context.js +42 -0
  282. package/dist/stateful/stateful-provider-adapter-metrics.d.ts +15 -0
  283. package/dist/stateful/stateful-provider-adapter-metrics.js +21 -0
  284. package/dist/stateful/stateful-provider-adapter.d.ts +98 -0
  285. package/dist/stateful/stateful-provider-adapter.js +287 -0
  286. package/dist/stateful/stateful-provider-observability.d.ts +62 -0
  287. package/dist/stateful/stateful-provider-observability.js +161 -0
  288. package/dist/stateful/stateful-provider-owner-forwarder.d.ts +41 -0
  289. package/dist/stateful/stateful-provider-owner-forwarder.js +237 -0
  290. package/dist/stateful/stateful-provider-runtime-context.d.ts +35 -0
  291. package/dist/stateful/stateful-provider-runtime-context.js +61 -0
  292. package/dist/stateful/stateful-provider-runtime-executor.d.ts +34 -0
  293. package/dist/stateful/stateful-provider-runtime-executor.js +52 -0
  294. package/dist/stateful/stateful-provider-session-routing.d.ts +67 -0
  295. package/dist/stateful/stateful-provider-session-routing.js +345 -0
  296. package/dist/stateful/stateful-provider-session-runtime.d.ts +98 -0
  297. package/dist/stateful/stateful-provider-session-runtime.js +245 -0
  298. package/dist/stateful-signing.d.ts +18 -0
  299. package/dist/stateful-signing.js +27 -0
  300. package/dist/stealth/profiles.d.ts +15 -4
  301. package/dist/stealth/profiles.js +169 -211
  302. package/dist/stream-evidence.d.ts +74 -0
  303. package/dist/stream-evidence.js +785 -0
  304. package/dist/stream.js +7 -1
  305. package/dist/testing/index.d.ts +2 -1
  306. package/dist/testing/index.js +2 -1
  307. package/dist/testing/run.d.ts +32 -2
  308. package/dist/testing/run.js +509 -25
  309. package/dist/trace-sanitization.d.ts +6 -0
  310. package/dist/trace-sanitization.js +68 -0
  311. package/dist/types.d.ts +899 -210
  312. package/dist/types.js +1 -0
  313. package/dist/typescript-module.d.ts +39 -0
  314. package/dist/typescript-module.js +72 -0
  315. package/package.json +52 -6
  316. package/src/auth-turn/index.ts +1 -1
  317. package/src/auth.ts +118 -0
  318. package/src/ceremonies/index.ts +189 -46
  319. package/src/cli/commands.ts +37 -0
  320. package/src/cli/create.ts +8 -2
  321. package/src/cli/deployment-intent.ts +364 -0
  322. package/src/cli/local-connection.ts +221 -0
  323. package/src/cli/migrate-deployment-intent.ts +1908 -0
  324. package/src/cli/migrate-operation-declaration.ts +3026 -0
  325. package/src/cli/migrate-operation-shape.ts +184 -0
  326. package/src/cli/migrate-provider-shape.ts +778 -0
  327. package/src/cli/resolver-runtime.ts +72 -0
  328. package/src/cli/templates/provider/.agents/skills/health-checks-and-fail-closed/SKILL.md.tpl +141 -23
  329. package/src/cli/templates/provider/Dockerfile.tpl +1 -1
  330. package/src/cli/templates/provider/README.md.tpl +41 -19
  331. package/src/cli/templates/provider/index.ts.tpl +6 -3
  332. package/src/cli/templates/provider/operations/ping.ts.tpl +4 -1
  333. package/src/cli/templates/provider/provider.json.tpl +6 -0
  334. package/src/config/loader.ts +774 -181
  335. package/src/contract-serialization.ts +5 -7
  336. package/src/contract-types.ts +12 -5
  337. package/src/contract.ts +24 -10
  338. package/src/declaration-validation.ts +376 -0
  339. package/src/define.ts +1105 -131
  340. package/src/dev.ts +13 -1
  341. package/src/engine.ts +390 -0
  342. package/src/error-observability.ts +64 -0
  343. package/src/error-resolution.ts +269 -0
  344. package/src/errors.ts +157 -0
  345. package/src/fixture-sanitization.ts +422 -0
  346. package/src/handle-meta.ts +143 -0
  347. package/src/handle.ts +694 -0
  348. package/src/health-scenario.ts +960 -0
  349. package/src/i18n/catalog.ts +23 -1
  350. package/src/i18n/error-messages.ts +255 -0
  351. package/src/i18n/index.ts +1 -0
  352. package/src/i18n/keys.ts +80 -6
  353. package/src/i18n/operation-locale-namespace.ts +10 -0
  354. package/src/index.ts +390 -23
  355. package/src/lint.ts +2975 -234
  356. package/src/native-address.ts +340 -0
  357. package/src/native-egress-policy.ts +358 -0
  358. package/src/observability.ts +51 -1
  359. package/src/provider.ts +207 -27
  360. package/src/runtime/auth-flow.ts +15 -0
  361. package/src/runtime/bounded-expiring-map.ts +67 -0
  362. package/src/runtime/browser-telemetry-binding.ts +92 -0
  363. package/src/runtime/browser-telemetry.ts +289 -0
  364. package/src/runtime/browser.ts +882 -99
  365. package/src/runtime/cache-telemetry.ts +247 -0
  366. package/src/runtime/cache.ts +258 -22
  367. package/src/runtime/capability-response.ts +53 -0
  368. package/src/runtime/capability-telemetry.ts +101 -0
  369. package/src/runtime/chrome149-header-order.ts +330 -0
  370. package/src/runtime/diagnostic-env-values.ts +56 -0
  371. package/src/runtime/diagnostic-env.ts +65 -0
  372. package/src/runtime/diagnostic-redactor.ts +668 -0
  373. package/src/runtime/egress-lease.ts +341 -0
  374. package/src/runtime/engine-mode.ts +233 -0
  375. package/src/runtime/env.ts +15 -1
  376. package/src/runtime/executor.ts +39 -32
  377. package/src/runtime/handle-wordlist.ts +266 -0
  378. package/src/runtime/handle.ts +1180 -0
  379. package/src/runtime/http-telemetry-binding.ts +162 -0
  380. package/src/runtime/http-telemetry-guard.ts +208 -0
  381. package/src/runtime/http-telemetry.ts +292 -0
  382. package/src/runtime/http.ts +896 -150
  383. package/src/runtime/insights.ts +2 -2
  384. package/src/runtime/instrumentation.ts +628 -28
  385. package/src/runtime/native-network-errors.ts +99 -0
  386. package/src/runtime/native-network.ts +1853 -0
  387. package/src/runtime/native-telemetry.ts +366 -0
  388. package/src/runtime/ocr-telemetry.ts +308 -0
  389. package/src/runtime/ocr.ts +564 -0
  390. package/src/runtime/otlp.ts +468 -21
  391. package/src/runtime/provider.ts +15 -0
  392. package/src/runtime/proxy-errors.ts +12 -4
  393. package/src/runtime/proxy-nodemaven.ts +222 -0
  394. package/src/runtime/proxy-retry-policy.ts +12 -1
  395. package/src/runtime/proxy-telemetry.ts +358 -103
  396. package/src/runtime/redirect-hop-headers.ts +71 -0
  397. package/src/runtime/redirects.ts +215 -0
  398. package/src/runtime/redis.ts +7 -2
  399. package/src/runtime/request-options.ts +728 -1
  400. package/src/runtime/request-telemetry.ts +375 -0
  401. package/src/runtime/resolver-config.ts +18 -0
  402. package/src/runtime/resolver-public.ts +44 -0
  403. package/src/runtime/resolver-runtime-options.ts +50 -0
  404. package/src/runtime/resolver-shared.ts +113 -0
  405. package/src/runtime/resolver-span-attributes.ts +139 -0
  406. package/src/runtime/resolver-telemetry.ts +362 -0
  407. package/src/runtime/resolver-usage.ts +99 -0
  408. package/src/runtime/resolver-vendors/bindings.ts +61 -0
  409. package/src/runtime/resolver-vendors/browser.ts +591 -0
  410. package/src/runtime/resolver-vendors/capsolver.ts +727 -0
  411. package/src/runtime/resolver-vendors/hosts.ts +81 -0
  412. package/src/runtime/resolver-vendors/hypersolutions.ts +480 -0
  413. package/src/runtime/resolver-vendors/twocaptcha.ts +555 -0
  414. package/src/runtime/resolver-vendors/types.ts +261 -0
  415. package/src/runtime/resolver.ts +1543 -0
  416. package/src/runtime/state-telemetry.ts +298 -0
  417. package/src/runtime/state.ts +435 -89
  418. package/src/runtime/stealth-akamai-sbsd.ts +207 -0
  419. package/src/runtime/stealth-cookies.ts +155 -0
  420. package/src/runtime/stealth-owned-headers.ts +67 -0
  421. package/src/runtime/stealth-telemetry.ts +309 -0
  422. package/src/runtime/stealth.ts +2275 -372
  423. package/src/runtime/stt-telemetry.ts +282 -0
  424. package/src/runtime/stt.ts +96 -91
  425. package/src/runtime/timeout.ts +18 -0
  426. package/src/runtime/trace-config.ts +78 -0
  427. package/src/runtime/trace.ts +257 -35
  428. package/src/runtime-boundary-lint.ts +707 -0
  429. package/src/schema.ts +80 -2
  430. package/src/serve.ts +6 -1
  431. package/src/server/error-observability.ts +1 -0
  432. package/src/server/error-stack-frames.ts +214 -0
  433. package/src/server/index.ts +184 -2
  434. package/src/server/runtime-diagnostics.ts +522 -0
  435. package/src/server/sdk-version.ts +22 -0
  436. package/src/server/self-test-input-tokens.ts +29 -14
  437. package/src/server/self-test-redaction.ts +10 -40
  438. package/src/server/self-test.ts +205 -89
  439. package/src/server/sensitive-values.ts +211 -0
  440. package/src/server/serve-implementation.ts +4596 -0
  441. package/src/server/serve.ts +1 -1685
  442. package/src/server/state-backend-report.ts +185 -0
  443. package/src/server/trace-output.ts +189 -0
  444. package/src/server/types.ts +34 -1
  445. package/src/stateful/README.md +146 -0
  446. package/src/stateful/errors.ts +35 -0
  447. package/src/stateful/http-provider-event-emitter.ts +314 -0
  448. package/src/stateful/http-session-owner-registry.ts +306 -0
  449. package/src/stateful/index.ts +18 -0
  450. package/src/stateful/provider-event-delivery-failures.ts +80 -0
  451. package/src/stateful/provider-event-pipeline-metrics.ts +95 -0
  452. package/src/stateful/provider-event-pipeline.ts +61 -0
  453. package/src/stateful/provider-events.ts +462 -0
  454. package/src/stateful/session-key.ts +111 -0
  455. package/src/stateful/stateful-provider-adapter-context.ts +59 -0
  456. package/src/stateful/stateful-provider-adapter-metrics.ts +48 -0
  457. package/src/stateful/stateful-provider-adapter.ts +562 -0
  458. package/src/stateful/stateful-provider-observability.ts +261 -0
  459. package/src/stateful/stateful-provider-owner-forwarder.ts +310 -0
  460. package/src/stateful/stateful-provider-runtime-context.ts +96 -0
  461. package/src/stateful/stateful-provider-runtime-executor.ts +96 -0
  462. package/src/stateful/stateful-provider-session-routing.ts +546 -0
  463. package/src/stateful/stateful-provider-session-runtime.ts +403 -0
  464. package/src/stateful-signing.ts +46 -0
  465. package/src/stealth/profiles.ts +212 -231
  466. package/src/stream-evidence.ts +988 -0
  467. package/src/stream.ts +8 -1
  468. package/src/testing/index.ts +10 -1
  469. package/src/testing/run.ts +685 -19
  470. package/src/trace-sanitization.ts +110 -0
  471. package/src/types.ts +1014 -273
  472. package/src/typescript-module.ts +100 -0
  473. package/dist/choice-token.d.ts +0 -24
  474. package/dist/choice-token.js +0 -74
  475. package/dist/runtime/choice.d.ts +0 -15
  476. package/dist/runtime/choice.js +0 -413
  477. package/src/choice-token.ts +0 -165
  478. package/src/runtime/choice.ts +0 -686
@@ -0,0 +1,142 @@
1
+ import { normalizedResolverHostname } from "./resolver-vendors/hosts.js";
2
+ /**
3
+ * Live SBSD `<script src>` paths are per-site obfuscated (zozo.jp captures, 2026-08-28:
4
+ * `/EdTyEb8Lyxqf/9iGcpl/GmKux0/DXObrkm53w/B1p4AQ/ZCF5f/VoJN08X?v=<uuid>` on the
5
+ * `Access Denied` shape, `/SHO9K/...?v=<uuid>&t=<token>` on the behavioral-tile hard shape).
6
+ * `/.well-known/sbsd` is only the POST endpoint string inside the deobfuscated
7
+ * script, never the page's script path. The stable shape is a same-origin script whose `v`
8
+ * is a UUID; cache-busted bundles (`?v=abc123`, hashes, semver) never match it.
9
+ */
10
+ const SBSD_SCRIPT_VERSION = /^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/iu;
11
+ const SBSD_INTERSTITIAL_MAX_BYTES = 4_000;
12
+ const SBSD_SCRIPT_DISCOVERY_MAX_BYTES = 4 * 1_024 * 1_024;
13
+ const SBSD_CHALLENGE_TOKEN_MAX_BYTES = 1_024;
14
+ const SBSD_INTERSTITIAL_MARKER = /sec-bc-tile-container|Access Denied|Reference #\d|Pardon Our Interruption|cpr_chlge/iu;
15
+ function htmlAttribute(value) {
16
+ return value.replace(/&amp;/giu, "&");
17
+ }
18
+ function isDeclaredHost(url, allowedHosts) {
19
+ const hostname = normalizedResolverHostname(url.hostname);
20
+ return allowedHosts.some((host) => normalizedResolverHostname(host) === hostname);
21
+ }
22
+ export function findAkamaiSbsdScript(body, page) {
23
+ // Only markup carries the script tag; JSON and binary bodies skip the scan entirely.
24
+ if (!/^\s*</u.test(body) || Buffer.byteLength(body) > SBSD_SCRIPT_DISCOVERY_MAX_BYTES) {
25
+ return undefined;
26
+ }
27
+ let passiveScript;
28
+ for (const match of body.matchAll(/<script\b[^>]*\bsrc\s*=\s*["']([^"']+)["'][^>]*>/giu)) {
29
+ let script;
30
+ try {
31
+ // Relative sources resolve against the page URL, as the browser would.
32
+ script = new URL(htmlAttribute(match[1]), page);
33
+ }
34
+ catch {
35
+ continue;
36
+ }
37
+ const version = script.searchParams.get("v")?.trim();
38
+ if (script.origin !== page.origin || !version || !SBSD_SCRIPT_VERSION.test(version)) {
39
+ continue;
40
+ }
41
+ if (script.searchParams.get("t")?.trim())
42
+ return script;
43
+ passiveScript ??= script;
44
+ }
45
+ return passiveScript;
46
+ }
47
+ function isAkamaiSbsdInterstitial(body) {
48
+ return (Buffer.byteLength(body) < SBSD_INTERSTITIAL_MAX_BYTES && SBSD_INTERSTITIAL_MARKER.test(body));
49
+ }
50
+ function parseAkamaiSbsdChallengeToken(body) {
51
+ if (Buffer.byteLength(body) >= SBSD_INTERSTITIAL_MAX_BYTES)
52
+ return undefined;
53
+ let parsed;
54
+ try {
55
+ parsed = JSON.parse(body);
56
+ }
57
+ catch {
58
+ return undefined;
59
+ }
60
+ if (!parsed ||
61
+ typeof parsed !== "object" ||
62
+ Array.isArray(parsed) ||
63
+ !("cpr_chlge" in parsed) ||
64
+ parsed.cpr_chlge !== "true" ||
65
+ !("t" in parsed) ||
66
+ typeof parsed.t !== "string") {
67
+ return undefined;
68
+ }
69
+ const token = parsed.t.trim();
70
+ return token && Buffer.byteLength(token) <= SBSD_CHALLENGE_TOKEN_MAX_BYTES ? token : undefined;
71
+ }
72
+ export function detectAkamaiSbsdChallenge(response, pageUrl, jar, allowedHosts, state) {
73
+ let page;
74
+ try {
75
+ page = new URL(response.url ?? pageUrl);
76
+ }
77
+ catch {
78
+ return undefined;
79
+ }
80
+ if (!isDeclaredHost(page, allowedHosts))
81
+ return undefined;
82
+ const stateCookieName = jar.has("sbsd_o", page.toString())
83
+ ? "sbsd_o"
84
+ : jar.has("bm_so", page.toString())
85
+ ? "bm_so"
86
+ : undefined;
87
+ const interstitial = isAkamaiSbsdInterstitial(response.body);
88
+ // Without the state cookie (the jar already holds the Set-Cookie of this very response;
89
+ // the live capture sets bm_so on the page that carries the script) or an interstitial,
90
+ // nothing here is Akamai's: do not scan, and do not let an unrelated UUID-versioned
91
+ // bundle become the remembered script.
92
+ if (!stateCookieName && !interstitial)
93
+ return undefined;
94
+ const currentScript = findAkamaiSbsdScript(response.body, page);
95
+ if (currentScript) {
96
+ const version = currentScript.searchParams.get("v")?.trim();
97
+ if (version) {
98
+ // Clone rather than re-parse the pathname: a `//x` path would re-parse as a host.
99
+ const rememberedScript = new URL(currentScript);
100
+ rememberedScript.search = "";
101
+ rememberedScript.hash = "";
102
+ rememberedScript.searchParams.set("v", version);
103
+ state.rememberedScript = rememberedScript;
104
+ }
105
+ }
106
+ if (!stateCookieName)
107
+ return undefined;
108
+ const laterToken = parseAkamaiSbsdChallengeToken(response.body);
109
+ const rememberedScript = state.rememberedScript;
110
+ if (laterToken && rememberedScript && rememberedScript.origin === page.origin) {
111
+ return {
112
+ kind: "akamai_sbsd",
113
+ pageUrl: page.toString(),
114
+ scriptUrl: rememberedScript.toString(),
115
+ stateCookieName,
116
+ challengeToken: laterToken,
117
+ };
118
+ }
119
+ if (!currentScript || !interstitial)
120
+ return undefined;
121
+ return {
122
+ kind: "akamai_sbsd",
123
+ pageUrl: page.toString(),
124
+ scriptUrl: currentScript.toString(),
125
+ stateCookieName,
126
+ };
127
+ }
128
+ /**
129
+ * One in-flight solve per session, challenge, and bound identity: requests on one session
130
+ * may still pick a different wreq browser/OS or proxy, and a solve is only valid for the
131
+ * identity that ran it.
132
+ */
133
+ export function akamaiSbsdChallengeKey(challenge, identity) {
134
+ return JSON.stringify([
135
+ new URL(challenge.scriptUrl).toString(),
136
+ challenge.challengeToken ?? "",
137
+ challenge.stateCookieName,
138
+ identity.wreqBrowser,
139
+ identity.wreqOs,
140
+ identity.proxyUrl ?? "",
141
+ ]);
142
+ }
@@ -0,0 +1,24 @@
1
+ import type { CookieJar, StealthCookieStore, StealthCookieStoreV1, StealthSessionCookies } from "../types.js";
2
+ /** Extract cookie values from Set-Cookie/header strings for request-scoped registration. */
3
+ export declare function cookieValuesFromHeaders(headers: string | readonly string[]): string[];
4
+ export declare class StealthCookieJar implements CookieJar, StealthSessionCookies {
5
+ private cookies;
6
+ private readonly defaultUrl;
7
+ private readonly register;
8
+ constructor(cookieStrings: readonly string[], defaultUrl?: string, register?: (value: string) => void);
9
+ setFromCookieStrings(cookieStrings: readonly string[], url?: string): void;
10
+ get(name: string, url?: string): string | undefined;
11
+ getAll(url?: string): Record<string, string>;
12
+ has(name: string, url?: string): boolean;
13
+ toString(url?: string): string;
14
+ toHeader(url?: string): string;
15
+ snapshot(): Record<string, string>;
16
+ restore(cookies: Record<string, string>): void;
17
+ serialize(): StealthCookieStoreV1;
18
+ deserialize(state: StealthCookieStore): void;
19
+ clear(): void;
20
+ find(predicate: (cookie: string) => boolean, url?: string): string | undefined;
21
+ names(url?: string): string[];
22
+ private normalizeUrl;
23
+ private getUniqueCookies;
24
+ }
@@ -0,0 +1,131 @@
1
+ import { Cookie, CookieJar as ToughCookieJar } from "tough-cookie";
2
+ import { SDKError, StealthCookieStoreVersionError } from "../errors.js";
3
+ function isRecord(value) {
4
+ return typeof value === "object" && value !== null;
5
+ }
6
+ const LEGACY_COOKIE_ORIGIN = "https://legacy-cookie.invalid/";
7
+ /** Extract cookie values from Set-Cookie/header strings for request-scoped registration. */
8
+ export function cookieValuesFromHeaders(headers) {
9
+ const values = [];
10
+ for (const header of typeof headers === "string" ? [headers] : headers) {
11
+ const cookie = Cookie.parse(header);
12
+ if (cookie?.value)
13
+ values.push(cookie.value);
14
+ }
15
+ return values;
16
+ }
17
+ export class StealthCookieJar {
18
+ cookies;
19
+ defaultUrl;
20
+ register;
21
+ constructor(cookieStrings, defaultUrl = LEGACY_COOKIE_ORIGIN, register) {
22
+ this.cookies = new ToughCookieJar(undefined, {
23
+ allowSecureOnLocal: false,
24
+ rejectPublicSuffixes: true,
25
+ });
26
+ this.defaultUrl = this.normalizeUrl(defaultUrl) ?? LEGACY_COOKIE_ORIGIN;
27
+ this.register = register;
28
+ this.setFromCookieStrings(cookieStrings);
29
+ }
30
+ setFromCookieStrings(cookieStrings, url = this.defaultUrl) {
31
+ const cookieUrl = this.normalizeUrl(url);
32
+ if (!cookieUrl)
33
+ return;
34
+ for (const cookieString of cookieStrings) {
35
+ for (const value of cookieValuesFromHeaders(cookieString))
36
+ this.register?.(value);
37
+ this.cookies.setCookieSync(cookieString, cookieUrl, { ignoreError: true });
38
+ }
39
+ }
40
+ get(name, url) {
41
+ return this.getAll(url)[name];
42
+ }
43
+ getAll(url) {
44
+ return Object.fromEntries(this.getUniqueCookies(url ?? this.defaultUrl).map((cookie) => [cookie.key, cookie.value]));
45
+ }
46
+ has(name, url) {
47
+ return Object.hasOwn(this.getAll(url), name);
48
+ }
49
+ toString(url) {
50
+ return this.getUniqueCookies(url ?? this.defaultUrl)
51
+ .map((cookie) => cookie.cookieString())
52
+ .join("; ");
53
+ }
54
+ toHeader(url) {
55
+ return this.toString(url);
56
+ }
57
+ snapshot() {
58
+ const entries = [];
59
+ for (const cookie of this.serialize().jar.cookies) {
60
+ if (typeof cookie.key === "string" && typeof cookie.value === "string" && cookie.key) {
61
+ entries.push([cookie.key, cookie.value]);
62
+ }
63
+ }
64
+ return Object.fromEntries(entries);
65
+ }
66
+ restore(cookies) {
67
+ this.clear();
68
+ for (const [name, value] of Object.entries(cookies)) {
69
+ if (!name)
70
+ continue;
71
+ this.register?.(value);
72
+ this.cookies.setCookieSync(new Cookie({ key: name, path: "/", value }), this.defaultUrl, {
73
+ ignoreError: true,
74
+ });
75
+ }
76
+ }
77
+ serialize() {
78
+ const jar = this.cookies.serializeSync();
79
+ if (!jar) {
80
+ throw new SDKError("Stealth cookie store could not be serialized", {
81
+ code: "stealth_cookie_store_serialize_failed",
82
+ });
83
+ }
84
+ return { version: 1, jar };
85
+ }
86
+ deserialize(state) {
87
+ const version = isRecord(state) ? state.version : undefined;
88
+ if (version !== 1) {
89
+ throw new StealthCookieStoreVersionError(version);
90
+ }
91
+ const restored = ToughCookieJar.deserializeSync(state.jar);
92
+ Reflect.set(restored, "allowSecureOnLocal", false);
93
+ this.cookies = restored;
94
+ }
95
+ clear() {
96
+ this.cookies.removeAllCookiesSync();
97
+ }
98
+ find(predicate, url) {
99
+ for (const cookie of this.getUniqueCookies(url ?? this.defaultUrl)) {
100
+ const cookieString = cookie.cookieString();
101
+ if (predicate(cookieString))
102
+ return cookieString;
103
+ }
104
+ return undefined;
105
+ }
106
+ names(url) {
107
+ return this.getUniqueCookies(url ?? this.defaultUrl).map((cookie) => cookie.key);
108
+ }
109
+ normalizeUrl(url) {
110
+ try {
111
+ return new URL(url).toString();
112
+ }
113
+ catch {
114
+ return undefined;
115
+ }
116
+ }
117
+ getUniqueCookies(url) {
118
+ const cookieUrl = this.normalizeUrl(url);
119
+ if (!cookieUrl)
120
+ return [];
121
+ const names = new Set();
122
+ return this.cookies.getCookiesSync(cookieUrl).filter((cookie) => {
123
+ if (cookie.value)
124
+ this.register?.(cookie.value);
125
+ if (names.has(cookie.key))
126
+ return false;
127
+ names.add(cookie.key);
128
+ return true;
129
+ });
130
+ }
131
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Header names the stealth transport owns.
3
+ *
4
+ * `ctx.stealth` composes these from the Chrome emulation and the request class,
5
+ * so a caller value is rejected at request time with `SDKError` code
6
+ * `STEALTH_HEADER_OVERRIDE_UNSUPPORTED` ({@link assertCallerHeadersSupported}).
7
+ * The offline test harness (`runStandardTests`) calls the same function on
8
+ * every `ctx.stealth` request it serves, so a provider test fails exactly where
9
+ * production would, whichever file or variable the header came from. That is
10
+ * the cross-file enforcement.
11
+ *
12
+ * The `browser-version-literal` lint reports a subset of these names — the
13
+ * `sec-fetch-*` and `sec-ch-ua*` families — in files that use `ctx.stealth`
14
+ * (`isReportedOwnedHeaderName` in lint.ts). Both read this module, so the lint
15
+ * cannot claim a rejection the runtime does not perform; it reports
16
+ * deliberately less than the runtime rejects (host, connection,
17
+ * accept-encoding and a non-literal user-agent stay silent — see that
18
+ * predicate for why), so a green `apifuse check` is not proof that no owned
19
+ * header is set.
20
+ *
21
+ * Kept off the stealth runtime: the only import is `errors.js`, whose own
22
+ * imports are type-only, so the lazily loaded CLI lint path does not pull the
23
+ * stealth runtime in.
24
+ */
25
+ export declare const SDK_OWNED_EXACT_CHROME_HEADERS: ReadonlySet<string>;
26
+ export declare const SDK_OWNED_CHROME_HEADER_PREFIX = "sec-fetch-";
27
+ /**
28
+ * True when `ctx.stealth` rejects a caller value for `name` (case-insensitive):
29
+ * an exact member of {@link SDK_OWNED_EXACT_CHROME_HEADERS} or any
30
+ * `sec-fetch-*` name.
31
+ */
32
+ export declare function isStealthOwnedHeaderName(name: string): boolean;
33
+ /**
34
+ * Throws `SDKError` `STEALTH_HEADER_OVERRIDE_UNSUPPORTED` for the first caller
35
+ * header `ctx.stealth` owns. An `undefined` value is skipped, as the transport
36
+ * drops it before sending. The stealth runtime and the offline test harness
37
+ * both call this, so the two cannot disagree about what is rejected.
38
+ */
39
+ export declare function assertCallerHeadersSupported(headers: Readonly<Record<string, string | readonly string[] | undefined>>): void;
@@ -0,0 +1,57 @@
1
+ import { SDKError } from "../errors.js";
2
+ /**
3
+ * Header names the stealth transport owns.
4
+ *
5
+ * `ctx.stealth` composes these from the Chrome emulation and the request class,
6
+ * so a caller value is rejected at request time with `SDKError` code
7
+ * `STEALTH_HEADER_OVERRIDE_UNSUPPORTED` ({@link assertCallerHeadersSupported}).
8
+ * The offline test harness (`runStandardTests`) calls the same function on
9
+ * every `ctx.stealth` request it serves, so a provider test fails exactly where
10
+ * production would, whichever file or variable the header came from. That is
11
+ * the cross-file enforcement.
12
+ *
13
+ * The `browser-version-literal` lint reports a subset of these names — the
14
+ * `sec-fetch-*` and `sec-ch-ua*` families — in files that use `ctx.stealth`
15
+ * (`isReportedOwnedHeaderName` in lint.ts). Both read this module, so the lint
16
+ * cannot claim a rejection the runtime does not perform; it reports
17
+ * deliberately less than the runtime rejects (host, connection,
18
+ * accept-encoding and a non-literal user-agent stay silent — see that
19
+ * predicate for why), so a green `apifuse check` is not proof that no owned
20
+ * header is set.
21
+ *
22
+ * Kept off the stealth runtime: the only import is `errors.js`, whose own
23
+ * imports are type-only, so the lazily loaded CLI lint path does not pull the
24
+ * stealth runtime in.
25
+ */
26
+ export const SDK_OWNED_EXACT_CHROME_HEADERS = new Set([
27
+ "host",
28
+ "connection",
29
+ "user-agent",
30
+ "sec-ch-ua",
31
+ "sec-ch-ua-mobile",
32
+ "sec-ch-ua-platform",
33
+ "accept-encoding",
34
+ ]);
35
+ export const SDK_OWNED_CHROME_HEADER_PREFIX = "sec-fetch-";
36
+ /**
37
+ * True when `ctx.stealth` rejects a caller value for `name` (case-insensitive):
38
+ * an exact member of {@link SDK_OWNED_EXACT_CHROME_HEADERS} or any
39
+ * `sec-fetch-*` name.
40
+ */
41
+ export function isStealthOwnedHeaderName(name) {
42
+ const lower = name.toLowerCase();
43
+ return (SDK_OWNED_EXACT_CHROME_HEADERS.has(lower) || lower.startsWith(SDK_OWNED_CHROME_HEADER_PREFIX));
44
+ }
45
+ /**
46
+ * Throws `SDKError` `STEALTH_HEADER_OVERRIDE_UNSUPPORTED` for the first caller
47
+ * header `ctx.stealth` owns. An `undefined` value is skipped, as the transport
48
+ * drops it before sending. The stealth runtime and the offline test harness
49
+ * both call this, so the two cannot disagree about what is rejected.
50
+ */
51
+ export function assertCallerHeadersSupported(headers) {
52
+ for (const [name, value] of Object.entries(headers)) {
53
+ if (value === undefined || !isStealthOwnedHeaderName(name))
54
+ continue;
55
+ throw new SDKError(`Stealth transport owns the "${name.toLowerCase()}" header; remove it from headers.`, { code: "STEALTH_HEADER_OVERRIDE_UNSUPPORTED" });
56
+ }
57
+ }
@@ -0,0 +1,92 @@
1
+ import type { StealthBrowser, StealthChallengeClassification, StealthOS, StealthProfileDescriptor } from "../types.js";
2
+ import { type ClosedEnum, type TelemetryContributor } from "./request-telemetry.js";
3
+ export type StealthTelemetryErrorCode = "transport_network_error" | "transport_timeout" | "transport_cancelled" | "upstream_http_error" | "response_too_large" | "proxy_connect_failed" | "PROXY_POOL_STALE" | "PROXY_EDGE_AUTH_REJECTED" | "PROXY_AUTH_IP_DENIED" | "PROXY_EDGE_TLS_REJECTED" | "PROXY_REQUIRED" | "other";
4
+ export type StealthTelemetryRequestClass = "navigation" | "script_navigation" | "form_post" | "xhr" | "post";
5
+ export type StealthTelemetryAttemptKind = "request" | "resolver" | "proxy_diagnostic";
6
+ export type StealthTelemetrySbsdOutcome = StealthChallengeClassification["outcome"] | "detected" | "refetch_clear";
7
+ export type StealthTelemetryDiagnostics = {
8
+ readonly name?: string;
9
+ readonly message?: string;
10
+ readonly code?: string;
11
+ };
12
+ export type StealthTelemetryAttemptEvent = {
13
+ readonly ms: number;
14
+ readonly status?: number;
15
+ readonly errorCode?: StealthTelemetryErrorCode;
16
+ readonly diagnostics?: StealthTelemetryDiagnostics;
17
+ readonly profileId: StealthProfileDescriptor;
18
+ readonly proxyUsed: boolean;
19
+ readonly requestClass: StealthTelemetryRequestClass;
20
+ readonly kind?: StealthTelemetryAttemptKind;
21
+ };
22
+ export type StealthTelemetrySbsdEvent = {
23
+ readonly detected: boolean;
24
+ readonly outcome?: StealthTelemetrySbsdOutcome;
25
+ };
26
+ export interface StealthTelemetrySink {
27
+ recordAttempt(event: StealthTelemetryAttemptEvent): void;
28
+ recordPoolRefresh(): void;
29
+ recordRedirectHop(): void;
30
+ recordSbsd(event?: StealthTelemetrySbsdEvent | StealthTelemetrySbsdOutcome): void;
31
+ recordSafeRefetch(): void;
32
+ }
33
+ export type StealthTelemetryAttemptSample = {
34
+ n: number;
35
+ ms: number;
36
+ status?: number;
37
+ e?: StealthTelemetryErrorCode;
38
+ kind?: StealthTelemetryAttemptKind;
39
+ diagnostics?: StealthTelemetryDiagnostics;
40
+ };
41
+ export type StealthTelemetryLogPayload = {
42
+ attempts: number;
43
+ poolRefreshes: number;
44
+ redirectHops: number;
45
+ profileId?: StealthProfileDescriptor;
46
+ proxyUsed: boolean;
47
+ requestClass?: StealthTelemetryRequestClass;
48
+ sbsdDetected?: boolean;
49
+ sbsdOutcome?: StealthTelemetrySbsdOutcome;
50
+ safeRefetch: number;
51
+ lastStatus?: number;
52
+ ms: number;
53
+ attemptSamples?: StealthTelemetryAttemptSample[];
54
+ attemptSamplesDropped?: number;
55
+ };
56
+ export type StealthTelemetryHeaderPayload = {
57
+ attempts: number;
58
+ poolRefreshes: number;
59
+ redirectHops: number;
60
+ profileId?: {
61
+ browser: ClosedEnum<StealthBrowser>;
62
+ os: ClosedEnum<StealthOS>;
63
+ };
64
+ proxyUsed: boolean;
65
+ requestClass?: ClosedEnum<StealthTelemetryRequestClass>;
66
+ sbsdDetected?: boolean;
67
+ sbsdOutcome?: ClosedEnum<StealthTelemetrySbsdOutcome>;
68
+ safeRefetch: number;
69
+ lastStatus?: number;
70
+ ms: number;
71
+ attemptSamples?: {
72
+ n: number;
73
+ ms: number;
74
+ status?: number;
75
+ e?: ClosedEnum<StealthTelemetryErrorCode>;
76
+ kind?: ClosedEnum<StealthTelemetryAttemptKind>;
77
+ }[];
78
+ };
79
+ export declare class StealthTelemetryCollector implements StealthTelemetrySink, TelemetryContributor<StealthTelemetryLogPayload, StealthTelemetryHeaderPayload> {
80
+ #private;
81
+ readonly key: "stealth";
82
+ constructor(options?: {
83
+ redact?: (text: string) => string;
84
+ });
85
+ recordAttempt(event: StealthTelemetryAttemptEvent): void;
86
+ recordPoolRefresh(): void;
87
+ recordRedirectHop(): void;
88
+ recordSbsd(event?: StealthTelemetrySbsdEvent | StealthTelemetrySbsdOutcome): void;
89
+ recordSafeRefetch(): void;
90
+ toLogPayload(): StealthTelemetryLogPayload | undefined;
91
+ toHeaderPayload(log: StealthTelemetryLogPayload): StealthTelemetryHeaderPayload;
92
+ }
@@ -0,0 +1,179 @@
1
+ import { Buffer } from "node:buffer";
2
+ import { closedEnum } from "./request-telemetry.js";
3
+ const MAX_ATTEMPT_SAMPLES = 24;
4
+ const MAX_DIAGNOSTIC_TEXT = 300;
5
+ function boundedInteger(value) {
6
+ if (!Number.isFinite(value))
7
+ return Number.MAX_SAFE_INTEGER;
8
+ return Math.min(Number.MAX_SAFE_INTEGER, Math.max(0, Math.floor(value)));
9
+ }
10
+ function saturatingAdd(a, b) {
11
+ if (!Number.isFinite(a) || !Number.isFinite(b))
12
+ return Number.MAX_SAFE_INTEGER;
13
+ return Math.min(Number.MAX_SAFE_INTEGER, boundedInteger(a) + boundedInteger(b));
14
+ }
15
+ function boundedText(value, redact) {
16
+ let result = value;
17
+ try {
18
+ result = redact?.(value) ?? value;
19
+ }
20
+ catch {
21
+ result = "[REDACTION_FAILED]";
22
+ }
23
+ const length = Math.min(result.length, MAX_DIAGNOSTIC_TEXT);
24
+ const units = Buffer.alloc(length * 2);
25
+ for (let index = 0; index < length; index += 1) {
26
+ units.writeUInt16LE(result.charCodeAt(index), index * 2);
27
+ }
28
+ return units.toString("utf16le");
29
+ }
30
+ function cloneDiagnostics(diagnostics, redact) {
31
+ if (!diagnostics)
32
+ return undefined;
33
+ const result = {
34
+ ...(diagnostics.name === undefined ? {} : { name: boundedText(diagnostics.name, redact) }),
35
+ ...(diagnostics.message === undefined
36
+ ? {}
37
+ : { message: boundedText(diagnostics.message, redact) }),
38
+ ...(diagnostics.code === undefined ? {} : { code: boundedText(diagnostics.code, redact) }),
39
+ };
40
+ return Object.keys(result).length > 0 ? result : undefined;
41
+ }
42
+ function cloneProfile(profile) {
43
+ return { browser: profile.browser, os: profile.os };
44
+ }
45
+ export class StealthTelemetryCollector {
46
+ key = "stealth";
47
+ #redact;
48
+ #attempts = 0;
49
+ #poolRefreshes = 0;
50
+ #redirectHops = 0;
51
+ #profileId;
52
+ #proxyUsed = false;
53
+ #requestClass;
54
+ #sbsdDetected;
55
+ #sbsdOutcome;
56
+ #safeRefetch = 0;
57
+ #lastStatus;
58
+ #ms = 0;
59
+ #attemptSamples = [];
60
+ #attemptSamplesDropped = 0;
61
+ constructor(options = {}) {
62
+ this.#redact = options.redact;
63
+ }
64
+ recordAttempt(event) {
65
+ const ms = boundedInteger(event.ms);
66
+ this.#attempts = saturatingAdd(this.#attempts, 1);
67
+ this.#ms = saturatingAdd(this.#ms, ms);
68
+ this.#profileId = cloneProfile(event.profileId);
69
+ this.#proxyUsed ||= event.proxyUsed;
70
+ this.#requestClass = event.requestClass;
71
+ if (event.status !== undefined)
72
+ this.#lastStatus = boundedInteger(event.status);
73
+ if (this.#attemptSamples.length >= MAX_ATTEMPT_SAMPLES) {
74
+ this.#attemptSamplesDropped = saturatingAdd(this.#attemptSamplesDropped, 1);
75
+ return;
76
+ }
77
+ const sample = {
78
+ n: this.#attempts,
79
+ ms,
80
+ ...(event.status === undefined ? {} : { status: boundedInteger(event.status) }),
81
+ ...(event.errorCode === undefined ? {} : { e: event.errorCode }),
82
+ ...(event.kind === undefined ? {} : { kind: event.kind }),
83
+ ...(event.diagnostics
84
+ ? { diagnostics: cloneDiagnostics(event.diagnostics, this.#redact) }
85
+ : {}),
86
+ };
87
+ if (sample.diagnostics === undefined)
88
+ delete sample.diagnostics;
89
+ this.#attemptSamples.push(sample);
90
+ }
91
+ recordPoolRefresh() {
92
+ this.#poolRefreshes = saturatingAdd(this.#poolRefreshes, 1);
93
+ }
94
+ recordRedirectHop() {
95
+ this.#redirectHops = saturatingAdd(this.#redirectHops, 1);
96
+ }
97
+ recordSbsd(event) {
98
+ if (typeof event === "string") {
99
+ this.#sbsdDetected = true;
100
+ this.#sbsdOutcome = event;
101
+ return;
102
+ }
103
+ if (!event)
104
+ return;
105
+ this.#sbsdDetected = (this.#sbsdDetected ?? false) || event.detected;
106
+ if (event.outcome !== undefined)
107
+ this.#sbsdOutcome = event.outcome;
108
+ }
109
+ recordSafeRefetch() {
110
+ this.#safeRefetch = saturatingAdd(this.#safeRefetch, 1);
111
+ }
112
+ toLogPayload() {
113
+ if (this.#attempts === 0 &&
114
+ this.#poolRefreshes === 0 &&
115
+ this.#redirectHops === 0 &&
116
+ this.#safeRefetch === 0 &&
117
+ this.#sbsdDetected === undefined) {
118
+ return undefined;
119
+ }
120
+ return {
121
+ attempts: this.#attempts,
122
+ poolRefreshes: this.#poolRefreshes,
123
+ redirectHops: this.#redirectHops,
124
+ ...(this.#profileId ? { profileId: cloneProfile(this.#profileId) } : {}),
125
+ proxyUsed: this.#proxyUsed,
126
+ ...(this.#requestClass ? { requestClass: this.#requestClass } : {}),
127
+ ...(this.#sbsdDetected === undefined ? {} : { sbsdDetected: this.#sbsdDetected }),
128
+ ...(this.#sbsdOutcome ? { sbsdOutcome: this.#sbsdOutcome } : {}),
129
+ safeRefetch: this.#safeRefetch,
130
+ ...(this.#lastStatus === undefined ? {} : { lastStatus: this.#lastStatus }),
131
+ ms: this.#ms,
132
+ ...(this.#attemptSamples.length > 0
133
+ ? {
134
+ attemptSamples: this.#attemptSamples.map((sample) => ({
135
+ ...sample,
136
+ ...(sample.diagnostics
137
+ ? {
138
+ diagnostics: { ...sample.diagnostics },
139
+ }
140
+ : {}),
141
+ })),
142
+ }
143
+ : {}),
144
+ ...(this.#attemptSamplesDropped > 0
145
+ ? { attemptSamplesDropped: this.#attemptSamplesDropped }
146
+ : {}),
147
+ };
148
+ }
149
+ toHeaderPayload(log) {
150
+ const attemptSamples = log.attemptSamples?.map((sample) => ({
151
+ n: sample.n,
152
+ ms: sample.ms,
153
+ ...(sample.status === undefined ? {} : { status: sample.status }),
154
+ ...(sample.e ? { e: closedEnum(sample.e) } : {}),
155
+ ...(sample.kind ? { kind: closedEnum(sample.kind) } : {}),
156
+ }));
157
+ return {
158
+ attempts: log.attempts,
159
+ poolRefreshes: log.poolRefreshes,
160
+ redirectHops: log.redirectHops,
161
+ ...(log.profileId
162
+ ? {
163
+ profileId: {
164
+ browser: closedEnum(log.profileId.browser),
165
+ os: closedEnum(log.profileId.os),
166
+ },
167
+ }
168
+ : {}),
169
+ proxyUsed: log.proxyUsed,
170
+ ...(log.requestClass ? { requestClass: closedEnum(log.requestClass) } : {}),
171
+ ...(log.sbsdDetected === undefined ? {} : { sbsdDetected: log.sbsdDetected }),
172
+ ...(log.sbsdOutcome ? { sbsdOutcome: closedEnum(log.sbsdOutcome) } : {}),
173
+ safeRefetch: log.safeRefetch,
174
+ ...(log.lastStatus === undefined ? {} : { lastStatus: log.lastStatus }),
175
+ ms: log.ms,
176
+ ...(attemptSamples && attemptSamples.length > 0 ? { attemptSamples } : {}),
177
+ };
178
+ }
179
+ }