@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,139 @@
1
+ import type { ProxyUserAgentSource } from "../config/loader.js";
2
+ import type { ProviderChallengeKind, ProviderResolverVendor } from "../types.js";
3
+ import type { ResolverTelemetryPhase } from "./resolver-telemetry.js";
4
+ import type {
5
+ ResolverPaidUsageBilling,
6
+ ResolverPaidUsageEndpoint,
7
+ ResolverPaidUsageOutcome,
8
+ } from "./resolver-usage.js";
9
+ import type {
10
+ ResolverChallengeVerdictReason,
11
+ ResolverVendorUnavailableReason,
12
+ } from "./resolver-vendors/types.js";
13
+
14
+ // Type-only imports: the diagnostic redactor reads this table, so it must not pull the resolver
15
+ // runtime (or anything that imports the redactor) into module evaluation.
16
+
17
+ /** Every member of a closed string union, as runtime values; a missing or extra member fails tsc. */
18
+ function closedEnumValues<TUnion extends string>() {
19
+ return <const TValues extends readonly TUnion[]>(
20
+ values: TValues,
21
+ ..._missing: Exclude<TUnion, TValues[number]> extends never
22
+ ? []
23
+ : ["Missing closed-enum values", Exclude<TUnion, TValues[number]>]
24
+ ): TValues => values;
25
+ }
26
+
27
+ const RESOLVER_PAID_USAGE_OUTCOMES = closedEnumValues<ResolverPaidUsageOutcome>()([
28
+ "success",
29
+ "vendor_error",
30
+ "timeout",
31
+ "abandoned",
32
+ ]);
33
+ // `resolver.cache.invalidate` outcomes. The union stays private to resolver.ts; its producer's
34
+ // `resolverSpanAttributes` call fails to compile if it can emit an outcome missing here.
35
+ const RESOLVER_CACHE_INVALIDATION_OUTCOMES = [
36
+ "cache_disabled",
37
+ "entry_deleted",
38
+ "index_entry_deleted",
39
+ "not_cookie_solution",
40
+ "solution_not_cached",
41
+ ] as const;
42
+
43
+ /**
44
+ * Closed-enum span attributes emitted by the resolver, by attribute key. A value listed here is an
45
+ * SDK-declared literal, so fail-closed diagnostic redaction keeps it the way it keeps a typed
46
+ * number; any other value under the same key is still free text. Registered credentials are
47
+ * matched either way.
48
+ */
49
+ export const RESOLVER_CLOSED_ENUM_SPAN_ATTRIBUTES = {
50
+ vendor: closedEnumValues<ProviderResolverVendor>()([
51
+ "browser",
52
+ "capsolver",
53
+ "capmonster",
54
+ "2captcha",
55
+ "hypersolutions",
56
+ "custom",
57
+ ]),
58
+ challenge_kind: closedEnumValues<ProviderChallengeKind>()([
59
+ "turnstile",
60
+ "recaptcha_v2",
61
+ "recaptcha_v3",
62
+ "hcaptcha",
63
+ "cloudflare_interstitial",
64
+ "aws_waf",
65
+ "akamai_sec_cpt",
66
+ "akamai_sensor",
67
+ "akamai_sbsd",
68
+ ]),
69
+ endpoint: closedEnumValues<ResolverPaidUsageEndpoint>()([
70
+ "capsolver:create_task",
71
+ "twocaptcha:create_task",
72
+ "hyper:ip",
73
+ "hyper:sbsd_create",
74
+ ]),
75
+ billing: closedEnumValues<ResolverPaidUsageBilling>()(["metered", "unconfirmed"]),
76
+ outcome: [...RESOLVER_PAID_USAGE_OUTCOMES, ...RESOLVER_CACHE_INVALIDATION_OUTCOMES],
77
+ unavailability_reason: closedEnumValues<ResolverVendorUnavailableReason>()([
78
+ "missing_credentials",
79
+ "missing_proxy_identity",
80
+ "missing_client_profile",
81
+ "missing_challenge_input",
82
+ "missing_transport",
83
+ "allocation_exhausted",
84
+ "transport_failure",
85
+ "timeout",
86
+ "not_implemented",
87
+ ]),
88
+ verdict_reason: closedEnumValues<ResolverChallengeVerdictReason>()([
89
+ "human_puzzle",
90
+ "solve_failed",
91
+ ]),
92
+ transport_phase: closedEnumValues<ResolverTelemetryPhase>()([
93
+ "create_task",
94
+ "poll_result",
95
+ "cleanup",
96
+ "measure_ip",
97
+ "fetch_script",
98
+ "generate_payload",
99
+ "post_payload",
100
+ ]),
101
+ resolver_identity_source: closedEnumValues<ProxyUserAgentSource>()(["declared", "defaulted"]),
102
+ operation: closedEnumValues<"client.close" | "context.close">()([
103
+ "client.close",
104
+ "context.close",
105
+ ]),
106
+ } as const;
107
+
108
+ type ResolverClosedEnumSpanAttributes = typeof RESOLVER_CLOSED_ENUM_SPAN_ATTRIBUTES;
109
+ type Present<T> = Exclude<T, undefined>;
110
+ /** Properties typed as a finite union of string literals, never plain `string`. */
111
+ type FiniteStringKeys<T> = {
112
+ [K in keyof T]-?: [Present<T[K]>] extends [never]
113
+ ? never
114
+ : [Present<T[K]>] extends [string]
115
+ ? string extends Present<T[K]>
116
+ ? never
117
+ : K
118
+ : never;
119
+ }[keyof T];
120
+ type DeclaredClosedEnumAttributes<T> = {
121
+ [K in keyof T]: K extends FiniteStringKeys<T>
122
+ ? K extends keyof ResolverClosedEnumSpanAttributes
123
+ ? [Present<T[K]>] extends [ResolverClosedEnumSpanAttributes[K][number]]
124
+ ? T[K]
125
+ : never
126
+ : never
127
+ : T[K];
128
+ };
129
+
130
+ /**
131
+ * Resolver span attributes. Every property typed as a finite string union must be declared in
132
+ * `RESOLVER_CLOSED_ENUM_SPAN_ATTRIBUTES` with all of its members, so a new closed-enum attribute
133
+ * cannot silently become free text that fail-closed redaction suppresses.
134
+ */
135
+ export function resolverSpanAttributes<const T extends Record<string, unknown>>(
136
+ attributes: T & DeclaredClosedEnumAttributes<T>,
137
+ ): T {
138
+ return attributes;
139
+ }
@@ -0,0 +1,362 @@
1
+ import { Buffer } from "node:buffer";
2
+ import type { ProviderChallengeKind, ProviderResolverVendor } from "../types.js";
3
+ import { closedEnum, type ClosedEnum, type TelemetryContributor } from "./request-telemetry.js";
4
+ import type { ResolverVendorUnavailableReason } from "./resolver-vendors/types.js";
5
+
6
+ /**
7
+ * Result of the resolver call. `solved` means the adapter returned a solution;
8
+ * for SBSD this means payload acceptance, even when `verified` is false.
9
+ * It does not assert that a later protected request succeeded. Stealth reports
10
+ * that verification separately through the refetch status and challenge outcome.
11
+ */
12
+ export type ResolverTelemetryOutcome = "solved" | "cached" | "exhausted" | "aborted" | "error";
13
+ export type ResolverTelemetryCacheStatus = "hit" | "miss" | "disabled" | "not_cacheable";
14
+ export type ResolverTelemetryIdentitySource = "declared" | "defaulted" | "none";
15
+ export type ResolverTelemetryPhase =
16
+ | "create_task"
17
+ | "poll_result"
18
+ | "cleanup"
19
+ | "measure_ip"
20
+ | "fetch_script"
21
+ | "generate_payload"
22
+ | "post_payload";
23
+ export type ResolverTelemetryAttemptOutcome = "ok" | "error";
24
+ export type ResolverTelemetryErrorClass =
25
+ | ResolverVendorUnavailableReason
26
+ | "aborted"
27
+ | "unexpected";
28
+ export type ResolverTelemetryCacheWriteReason = "no_expires" | "not_cacheable" | "error";
29
+
30
+ export type ResolverIdentityTelemetryEvent = {
31
+ readonly source: ResolverTelemetryIdentitySource;
32
+ readonly failure?: ResolverVendorUnavailableReason;
33
+ };
34
+
35
+ export type ResolverCacheReadTelemetryEvent = {
36
+ readonly status: ResolverTelemetryCacheStatus;
37
+ readonly challengeKind: ProviderChallengeKind;
38
+ };
39
+
40
+ export type ResolverCacheWriteTelemetryEvent = {
41
+ readonly written: boolean;
42
+ readonly reason?: ResolverTelemetryCacheWriteReason;
43
+ };
44
+
45
+ export type ResolverVendorAttemptTelemetryEvent = {
46
+ readonly vendor: ProviderResolverVendor;
47
+ readonly phase: ResolverTelemetryPhase;
48
+ readonly outcome: ResolverTelemetryAttemptOutcome;
49
+ readonly ms: number;
50
+ readonly pollCount?: number;
51
+ readonly errorClass?: ResolverTelemetryErrorClass;
52
+ readonly vendorErrorCode?: string;
53
+ readonly vendorErrorDescription?: string;
54
+ /** Operator-only diagnostics; free text is redacted, detached and bounded by the collector. */
55
+ readonly diagnostics?: {
56
+ readonly cause?: { readonly name: string; readonly message: string };
57
+ readonly upstreamHost?: string;
58
+ readonly missingFields?: readonly string[];
59
+ readonly round?: number;
60
+ /** One-based position in the supporting vendor chain. */
61
+ readonly attemptIndex?: number;
62
+ /** Actual adapter phase, including phases outside the header's closed enum. */
63
+ readonly phase?: string;
64
+ };
65
+ };
66
+
67
+ export type ResolverFailoverTelemetryEvent = {
68
+ readonly from: ProviderResolverVendor;
69
+ readonly to: ProviderResolverVendor;
70
+ readonly reason: ResolverVendorUnavailableReason;
71
+ };
72
+
73
+ export type ResolverOutcomeTelemetryEvent = {
74
+ readonly outcome: ResolverTelemetryOutcome;
75
+ readonly solveMs: number;
76
+ readonly challengeKind: ProviderChallengeKind;
77
+ };
78
+
79
+ export interface ResolverTelemetrySink {
80
+ recordIdentity(event: ResolverIdentityTelemetryEvent): void;
81
+ recordCacheRead(event: ResolverCacheReadTelemetryEvent): void;
82
+ recordCacheWrite(event: ResolverCacheWriteTelemetryEvent): void;
83
+ recordVendorAttempt(event: ResolverVendorAttemptTelemetryEvent): void;
84
+ recordFailover(event: ResolverFailoverTelemetryEvent): void;
85
+ recordOutcome(event: ResolverOutcomeTelemetryEvent): void;
86
+ }
87
+
88
+ export type ResolverAttemptSample = {
89
+ v: ProviderResolverVendor;
90
+ p: ResolverTelemetryPhase;
91
+ o: ResolverTelemetryAttemptOutcome;
92
+ ms: number;
93
+ c?: string;
94
+ e?: ResolverTelemetryErrorClass;
95
+ diagnostics?: ResolverVendorAttemptTelemetryEvent["diagnostics"];
96
+ };
97
+
98
+ export type ResolverTelemetryLogPayload = {
99
+ /** Adapter result; `solved` includes unverified payload acceptance. Read the protected refetch status/challenge outcome for verification. */
100
+ outcome?: ResolverTelemetryOutcome;
101
+ challengeKind?: ProviderChallengeKind;
102
+ cacheStatus?: ResolverTelemetryCacheStatus;
103
+ cacheWrite?: {
104
+ written: boolean;
105
+ reason?: ResolverTelemetryCacheWriteReason;
106
+ };
107
+ identitySource?: ResolverTelemetryIdentitySource;
108
+ identityFailure?: ResolverVendorUnavailableReason;
109
+ solveMs?: number;
110
+ attempts: number;
111
+ failovers: number;
112
+ vendorChain: ProviderResolverVendor[];
113
+ vendorUsed?: ProviderResolverVendor;
114
+ pollCount: number;
115
+ attemptSamples?: ResolverAttemptSample[];
116
+ attemptSamplesDropped?: number;
117
+ lastVendorErrorDescription?: string;
118
+ };
119
+
120
+ export type ResolverTelemetryHeaderPayload = {
121
+ /** Same adapter-result semantics as the log outcome; `solved` does not imply protected-refetch success. */
122
+ outcome?: ClosedEnum<ResolverTelemetryOutcome>;
123
+ cacheStatus?: ClosedEnum<ResolverTelemetryCacheStatus>;
124
+ solveMs?: number;
125
+ attempts: number;
126
+ failovers: number;
127
+ vendorUsed?: ClosedEnum<ProviderResolverVendor>;
128
+ vendorChain: ClosedEnum<ProviderResolverVendor>[];
129
+ pollCount: number;
130
+ identitySource?: ClosedEnum<ResolverTelemetryIdentitySource>;
131
+ attemptSamples?: {
132
+ v: ClosedEnum<ProviderResolverVendor>;
133
+ p: ClosedEnum<ResolverTelemetryPhase>;
134
+ o: ClosedEnum<ResolverTelemetryAttemptOutcome>;
135
+ ms: number;
136
+ c?: ClosedEnum<string>;
137
+ }[];
138
+ };
139
+
140
+ const MAX_RESOLVER_ATTEMPT_SAMPLES = 24;
141
+ const MAX_RESOLVER_VENDOR_CHAIN = 64;
142
+ const MAX_DIAGNOSTIC_TEXT = 300;
143
+ const MAX_MISSING_FIELDS = 24;
144
+ const HEADER_TOKEN = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,63}$/;
145
+
146
+ function boundedInteger(value: number): number {
147
+ return Math.max(0, Math.floor(Number.isFinite(value) ? value : 0));
148
+ }
149
+
150
+ export function boundedText(value: string, redact?: (text: string) => string): string {
151
+ let result = value;
152
+ try {
153
+ result = redact?.(value) ?? value;
154
+ } catch {
155
+ return "[REDACTION_FAILED]";
156
+ }
157
+ // Copy code units through an independent UTF-16 buffer. A sliced string can
158
+ // otherwise keep a multi-megabyte vendor response alive in both JSC and V8.
159
+ // Preserve lone surrogates deliberately, including a pair split at the limit.
160
+ const length = Math.min(result.length, MAX_DIAGNOSTIC_TEXT);
161
+ const units = Buffer.alloc(length * 2);
162
+ for (let index = 0; index < length; index += 1) {
163
+ units.writeUInt16LE(result.charCodeAt(index), index * 2);
164
+ }
165
+ return units.toString("utf16le");
166
+ }
167
+
168
+ function boundedDiagnostics(
169
+ diagnostics: NonNullable<ResolverVendorAttemptTelemetryEvent["diagnostics"]>,
170
+ redact?: (text: string) => string,
171
+ ): NonNullable<ResolverAttemptSample["diagnostics"]> {
172
+ return {
173
+ ...(diagnostics.cause
174
+ ? {
175
+ cause: {
176
+ name: boundedText(diagnostics.cause.name, redact),
177
+ message: boundedText(diagnostics.cause.message, redact),
178
+ },
179
+ }
180
+ : {}),
181
+ ...(diagnostics.upstreamHost
182
+ ? { upstreamHost: boundedText(diagnostics.upstreamHost, redact) }
183
+ : {}),
184
+ ...(diagnostics.missingFields
185
+ ? {
186
+ missingFields: diagnostics.missingFields
187
+ .slice(0, MAX_MISSING_FIELDS)
188
+ .map((field) => boundedText(field, redact)),
189
+ }
190
+ : {}),
191
+ ...(diagnostics.round === undefined ? {} : { round: boundedInteger(diagnostics.round) }),
192
+ ...(diagnostics.attemptIndex === undefined
193
+ ? {}
194
+ : { attemptIndex: boundedInteger(diagnostics.attemptIndex) }),
195
+ ...(diagnostics.phase ? { phase: boundedText(diagnostics.phase, redact) } : {}),
196
+ };
197
+ }
198
+
199
+ export class ResolverTelemetryCollector
200
+ implements
201
+ ResolverTelemetrySink,
202
+ TelemetryContributor<ResolverTelemetryLogPayload, ResolverTelemetryHeaderPayload>
203
+ {
204
+ readonly key = "resolver" as const;
205
+ readonly #redact: ((text: string) => string) | undefined;
206
+ #identity: ResolverIdentityTelemetryEvent | undefined;
207
+ #cacheRead: ResolverCacheReadTelemetryEvent | undefined;
208
+ #cacheWrite: ResolverCacheWriteTelemetryEvent | undefined;
209
+ #outcome: ResolverOutcomeTelemetryEvent | undefined;
210
+ #attempts = 0;
211
+ #failovers = 0;
212
+ #pollCount = 0;
213
+ #vendorChain: ProviderResolverVendor[] = [];
214
+ #vendorUsed: ProviderResolverVendor | undefined;
215
+ #attemptSamples: ResolverAttemptSample[] = [];
216
+ #attemptSamplesDropped = 0;
217
+ #lastVendorErrorDescription: string | undefined;
218
+
219
+ constructor(options: { redact?: (text: string) => string } = {}) {
220
+ this.#redact = options.redact;
221
+ }
222
+
223
+ recordIdentity(event: ResolverIdentityTelemetryEvent): void {
224
+ this.#identity = { ...event };
225
+ }
226
+
227
+ recordCacheRead(event: ResolverCacheReadTelemetryEvent): void {
228
+ this.#cacheRead = { ...event };
229
+ }
230
+
231
+ recordCacheWrite(event: ResolverCacheWriteTelemetryEvent): void {
232
+ this.#cacheWrite = { ...event };
233
+ }
234
+
235
+ recordVendorAttempt(event: ResolverVendorAttemptTelemetryEvent): void {
236
+ const ms = boundedInteger(event.ms);
237
+ const pollCount = event.pollCount === undefined ? 0 : boundedInteger(event.pollCount);
238
+ this.#pollCount += pollCount;
239
+ if (event.phase !== "cleanup") {
240
+ this.#attempts += 1;
241
+ if (
242
+ this.#vendorChain.length < MAX_RESOLVER_VENDOR_CHAIN &&
243
+ this.#vendorChain.at(-1) !== event.vendor
244
+ ) {
245
+ this.#vendorChain.push(event.vendor);
246
+ }
247
+ if (event.outcome === "ok") this.#vendorUsed = event.vendor;
248
+ }
249
+ if (this.#attemptSamples.length < MAX_RESOLVER_ATTEMPT_SAMPLES) {
250
+ this.#attemptSamples.push({
251
+ v: event.vendor,
252
+ p: event.phase,
253
+ o: event.outcome,
254
+ ms,
255
+ ...(event.vendorErrorCode ? { c: boundedText(event.vendorErrorCode, this.#redact) } : {}),
256
+ ...(event.errorClass ? { e: event.errorClass } : {}),
257
+ ...(event.diagnostics
258
+ ? { diagnostics: boundedDiagnostics(event.diagnostics, this.#redact) }
259
+ : {}),
260
+ });
261
+ } else {
262
+ this.#attemptSamplesDropped += 1;
263
+ }
264
+ if (event.vendorErrorDescription) {
265
+ this.#lastVendorErrorDescription = boundedText(event.vendorErrorDescription, this.#redact);
266
+ }
267
+ }
268
+
269
+ recordFailover(_event: ResolverFailoverTelemetryEvent): void {
270
+ this.#failovers += 1;
271
+ }
272
+
273
+ recordOutcome(event: ResolverOutcomeTelemetryEvent): void {
274
+ this.#outcome = { ...event, solveMs: boundedInteger(event.solveMs) };
275
+ }
276
+
277
+ toLogPayload(): ResolverTelemetryLogPayload | undefined {
278
+ if (
279
+ !this.#identity &&
280
+ !this.#cacheRead &&
281
+ !this.#cacheWrite &&
282
+ !this.#outcome &&
283
+ this.#attempts === 0 &&
284
+ this.#attemptSamples.length === 0 &&
285
+ this.#failovers === 0
286
+ ) {
287
+ return undefined;
288
+ }
289
+ return {
290
+ ...(this.#outcome
291
+ ? {
292
+ outcome: this.#outcome.outcome,
293
+ challengeKind: this.#outcome.challengeKind,
294
+ solveMs: this.#outcome.solveMs,
295
+ }
296
+ : this.#cacheRead
297
+ ? { challengeKind: this.#cacheRead.challengeKind }
298
+ : {}),
299
+ ...(this.#cacheRead ? { cacheStatus: this.#cacheRead.status } : {}),
300
+ ...(this.#cacheWrite ? { cacheWrite: { ...this.#cacheWrite } } : {}),
301
+ ...(this.#identity
302
+ ? {
303
+ identitySource: this.#identity.source,
304
+ ...(this.#identity.failure ? { identityFailure: this.#identity.failure } : {}),
305
+ }
306
+ : {}),
307
+ attempts: this.#attempts,
308
+ failovers: this.#failovers,
309
+ vendorChain: [...this.#vendorChain],
310
+ ...(this.#vendorUsed ? { vendorUsed: this.#vendorUsed } : {}),
311
+ pollCount: this.#pollCount,
312
+ ...(this.#attemptSamples.length > 0
313
+ ? {
314
+ attemptSamples: this.#attemptSamples.map((sample) => ({
315
+ ...sample,
316
+ ...(sample.diagnostics
317
+ ? {
318
+ diagnostics: {
319
+ ...sample.diagnostics,
320
+ ...(sample.diagnostics.cause
321
+ ? { cause: { ...sample.diagnostics.cause } }
322
+ : {}),
323
+ ...(sample.diagnostics.missingFields
324
+ ? { missingFields: [...sample.diagnostics.missingFields] }
325
+ : {}),
326
+ },
327
+ }
328
+ : {}),
329
+ })),
330
+ }
331
+ : {}),
332
+ ...(this.#attemptSamplesDropped > 0
333
+ ? { attemptSamplesDropped: this.#attemptSamplesDropped }
334
+ : {}),
335
+ ...(this.#lastVendorErrorDescription
336
+ ? { lastVendorErrorDescription: this.#lastVendorErrorDescription }
337
+ : {}),
338
+ };
339
+ }
340
+
341
+ toHeaderPayload(log: ResolverTelemetryLogPayload): ResolverTelemetryHeaderPayload {
342
+ const attemptSamples = log.attemptSamples?.map((sample) => ({
343
+ v: closedEnum(sample.v),
344
+ p: closedEnum(sample.p),
345
+ o: closedEnum(sample.o),
346
+ ms: sample.ms,
347
+ ...(sample.c && HEADER_TOKEN.test(sample.c) ? { c: closedEnum(sample.c) } : {}),
348
+ }));
349
+ return {
350
+ ...(log.outcome ? { outcome: closedEnum(log.outcome) } : {}),
351
+ ...(log.cacheStatus ? { cacheStatus: closedEnum(log.cacheStatus) } : {}),
352
+ ...(log.solveMs === undefined ? {} : { solveMs: log.solveMs }),
353
+ attempts: log.attempts,
354
+ failovers: log.failovers,
355
+ ...(log.vendorUsed ? { vendorUsed: closedEnum(log.vendorUsed) } : {}),
356
+ vendorChain: log.vendorChain.map((vendor) => closedEnum(vendor)),
357
+ pollCount: log.pollCount,
358
+ ...(log.identitySource ? { identitySource: closedEnum(log.identitySource) } : {}),
359
+ ...(attemptSamples && attemptSamples.length > 0 ? { attemptSamples } : {}),
360
+ };
361
+ }
362
+ }
@@ -0,0 +1,99 @@
1
+ import type { ProviderChallengeKind, ProviderResolverVendor } from "../types.js";
2
+ import type {
3
+ ResolverPaidUsageContext,
4
+ ResolverVendorUnavailableError,
5
+ } from "./resolver-vendors/types.js";
6
+ import type { TraceRecorder } from "./trace.js";
7
+ import { resolverSpanAttributes } from "./resolver-span-attributes.js";
8
+
9
+ export const RESOLVER_PAID_USAGE_SPAN = "resolver.usage";
10
+
11
+ export type ResolverPaidUsageOutcome = "success" | "vendor_error" | "timeout" | "abandoned";
12
+
13
+ export type ResolverPaidUsageEndpoint =
14
+ | "capsolver:create_task"
15
+ | "twocaptcha:create_task"
16
+ | "hyper:ip"
17
+ | "hyper:sbsd_create";
18
+
19
+ /**
20
+ * How one call to the endpoint is counted. `metered` endpoints are the vendors' task or
21
+ * payload creation calls: the SDK counts one unit per call (the vendor ledger stays
22
+ * authoritative for refunds of failed tasks). Hyper's `/ip` reflector is authenticated
23
+ * but has no published price, so it is recorded with 0 units and `billing: "unconfirmed"`
24
+ * rather than invented as a paid unit; the span still proves the call was made.
25
+ */
26
+ export type ResolverPaidUsageBilling = "metered" | "unconfirmed";
27
+
28
+ const ENDPOINT_BILLING: Record<
29
+ ResolverPaidUsageEndpoint,
30
+ { readonly billable_units: 0 | 1; readonly billing: ResolverPaidUsageBilling }
31
+ > = {
32
+ "capsolver:create_task": { billable_units: 1, billing: "metered" },
33
+ "twocaptcha:create_task": { billable_units: 1, billing: "metered" },
34
+ "hyper:ip": { billable_units: 0, billing: "unconfirmed" },
35
+ "hyper:sbsd_create": { billable_units: 1, billing: "metered" },
36
+ };
37
+
38
+ function errorOutcome(error: unknown, signal: AbortSignal): ResolverPaidUsageOutcome {
39
+ const signalReason = signal.reason;
40
+ const errorName = error instanceof Error ? error.name : "";
41
+ const reasonName = signalReason instanceof Error ? signalReason.name : "";
42
+ const unavailableReason = (error as Partial<ResolverVendorUnavailableError> | undefined)?.reason;
43
+ if (
44
+ unavailableReason === "timeout" ||
45
+ /timeout/iu.test(errorName) ||
46
+ /timeout/iu.test(reasonName)
47
+ ) {
48
+ return "timeout";
49
+ }
50
+ if (signal.aborted) return "abandoned";
51
+ return "vendor_error";
52
+ }
53
+
54
+ const warnedSinks = new WeakSet<(message: string) => void>();
55
+
56
+ /**
57
+ * Records one `resolver.usage` span around a paid vendor call. Callers validate credentials
58
+ * and transport first, so a span means a potentially billable request was attempted (a
59
+ * failed create the vendor may still bill is a span too). Without a trace recorder the call
60
+ * still runs; the lost billing record is warned once per warn sink.
61
+ */
62
+ export async function recordPaidResolverCreate<T>(options: {
63
+ readonly traceRecorder?: TraceRecorder;
64
+ readonly vendor: ProviderResolverVendor;
65
+ readonly kind: ProviderChallengeKind;
66
+ readonly endpoint: ResolverPaidUsageEndpoint;
67
+ /** 1-based round for endpoints called more than once per solve (Hyper payload rounds). */
68
+ readonly round?: number;
69
+ readonly signal: AbortSignal;
70
+ readonly usage?: ResolverPaidUsageContext;
71
+ readonly warn?: (message: string) => void;
72
+ readonly create: () => Promise<T>;
73
+ }): Promise<T> {
74
+ if (!options.traceRecorder) {
75
+ const warn = options.warn ?? console.warn;
76
+ if (!warnedSinks.has(warn)) {
77
+ warnedSinks.add(warn);
78
+ warn(
79
+ `[provider-sdk] Paid resolver call ${options.endpoint} ran without a trace recorder; its resolver.usage record is lost (reported once).`,
80
+ );
81
+ }
82
+ return options.create();
83
+ }
84
+ const baseAttributes = resolverSpanAttributes({
85
+ vendor: options.vendor,
86
+ challenge_kind: options.kind,
87
+ endpoint: options.endpoint,
88
+ ...ENDPOINT_BILLING[options.endpoint],
89
+ // Only the resolver chain knows the vendor's position; a direct adapter call has none.
90
+ ...(options.usage ? { vendor_index: options.usage.vendorIndex } : {}),
91
+ ...(options.round === undefined ? {} : { round: options.round }),
92
+ resolver_identity_scope: options.usage?.resolverIdentityScope,
93
+ });
94
+ return options.traceRecorder.runSpan(RESOLVER_PAID_USAGE_SPAN, options.create, {
95
+ attributes: baseAttributes,
96
+ onSuccess: () => resolverSpanAttributes({ outcome: "success" }),
97
+ onError: (error) => resolverSpanAttributes({ outcome: errorOutcome(error, options.signal) }),
98
+ });
99
+ }
@@ -0,0 +1,61 @@
1
+ import type { ProviderChallenge, ProviderChallengeKind } from "../../types.js";
2
+ import type { ResolverIssuingIdentity } from "./types.js";
3
+
4
+ type ResolverChallengeBinding = {
5
+ readonly cacheable: boolean;
6
+ readonly identityBinding: "none" | "identity_scoped" | "portable";
7
+ readonly directCacheable: boolean;
8
+ };
9
+
10
+ // An IP-bound artifact minted without any recorded egress identity is unsafe to
11
+ // share. The Akamai kinds therefore reject direct caching, while Cloudflare
12
+ // keeps its pre-existing direct-cache behavior pending measurement.
13
+ export const RESOLVER_CHALLENGE_BINDINGS = {
14
+ turnstile: { cacheable: false, identityBinding: "none", directCacheable: false },
15
+ recaptcha_v2: { cacheable: false, identityBinding: "none", directCacheable: false },
16
+ recaptcha_v3: { cacheable: false, identityBinding: "none", directCacheable: false },
17
+ hcaptcha: { cacheable: false, identityBinding: "none", directCacheable: false },
18
+ cloudflare_interstitial: {
19
+ cacheable: true,
20
+ identityBinding: "identity_scoped",
21
+ directCacheable: true,
22
+ },
23
+ aws_waf: { cacheable: true, identityBinding: "portable", directCacheable: true },
24
+ akamai_sec_cpt: {
25
+ cacheable: true,
26
+ identityBinding: "identity_scoped",
27
+ directCacheable: false,
28
+ },
29
+ akamai_sensor: {
30
+ cacheable: true,
31
+ identityBinding: "identity_scoped",
32
+ directCacheable: false,
33
+ },
34
+ akamai_sbsd: {
35
+ cacheable: false,
36
+ identityBinding: "identity_scoped",
37
+ directCacheable: false,
38
+ },
39
+ } as const satisfies Readonly<Record<ProviderChallengeKind, ResolverChallengeBinding>>;
40
+
41
+ export function resolverChallengeIsCacheable(challenge: ProviderChallenge): boolean {
42
+ return RESOLVER_CHALLENGE_BINDINGS[challenge.kind].cacheable;
43
+ }
44
+
45
+ export function resolverChallengeAllowsDirectCache(challenge: ProviderChallenge): boolean {
46
+ return RESOLVER_CHALLENGE_BINDINGS[challenge.kind].directCacheable;
47
+ }
48
+
49
+ export function resolverChallengeIsIdentityScoped(challenge: ProviderChallenge): boolean {
50
+ return RESOLVER_CHALLENGE_BINDINGS[challenge.kind].identityBinding === "identity_scoped";
51
+ }
52
+
53
+ export function resolverChallengeIssuingIdentity(
54
+ challenge: ProviderChallenge,
55
+ identity: ResolverIssuingIdentity,
56
+ ): ResolverIssuingIdentity {
57
+ if (RESOLVER_CHALLENGE_BINDINGS[challenge.kind].identityBinding === "portable") {
58
+ return { userAgent: identity.userAgent };
59
+ }
60
+ return identity;
61
+ }