@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
@@ -1,7 +1,7 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
- import { readFileSync } from "node:fs";
3
2
 
4
3
  import { TURN_KINDS } from "../auth-turn/index.js";
4
+ import { SDK_VERSION } from "./sdk-version.js";
5
5
 
6
6
  import { type Context, Hono } from "hono";
7
7
  import { z } from "zod";
@@ -77,11 +77,22 @@ export interface SelfTestResponse {
77
77
  results: SelfTestCaseResult[];
78
78
  }
79
79
 
80
+ export interface SelfTestCancellationLogEvent {
81
+ level: "info";
82
+ event: "self_test_run_cancelled";
83
+ providerId: string;
84
+ requestId: string;
85
+ operationId: string;
86
+ caseName: string;
87
+ reason: string;
88
+ }
89
+
80
90
  export type SelfTestOperationInvoke = (args: {
81
91
  operationId: string;
82
92
  input: unknown;
83
93
  connection?: OperationConnection;
84
94
  requestId: string;
95
+ signal?: AbortSignal;
85
96
  }) => Promise<{
86
97
  status: number;
87
98
  data: unknown;
@@ -106,6 +117,9 @@ export type SelfTestAuthFlowInvoke = (args: {
106
117
  externalRef?: string;
107
118
  input?: Record<string, unknown>;
108
119
  context?: Record<string, unknown>;
120
+ /** Opaque engine state from the previous turn (`engine` in the auth response), sent verbatim. */
121
+ engine?: { egressLease: string };
122
+ signal?: AbortSignal;
109
123
  }) => Promise<{
110
124
  status: number;
111
125
  body: unknown;
@@ -165,28 +179,10 @@ export interface SelfTestAppOptions {
165
179
  requestBudgetMs?: number;
166
180
  /** Env override for secret collection + budget resolution (tests). */
167
181
  env?: Readonly<Record<string, string | undefined>>;
182
+ /** Structured server logger; defaults to the same JSON console shape as the provider server. */
183
+ logger?: (event: SelfTestCancellationLogEvent) => void;
168
184
  }
169
185
 
170
- function resolveSdkVersion(): string {
171
- try {
172
- const packageJsonUrl = new URL("../../package.json", import.meta.url);
173
- const parsed: unknown = JSON.parse(readFileSync(packageJsonUrl, "utf8"));
174
- if (
175
- parsed &&
176
- typeof parsed === "object" &&
177
- "version" in parsed &&
178
- typeof (parsed as { version: unknown }).version === "string"
179
- ) {
180
- return (parsed as { version: string }).version;
181
- }
182
- } catch {
183
- // fall through to unknown
184
- }
185
- return "unknown";
186
- }
187
-
188
- const SDK_VERSION = resolveSdkVersion();
189
-
190
186
  type AnyHealthCheckSuite = HealthCheckSuite<unknown, unknown>;
191
187
  type AnyHealthCheckCase = HealthCheckCase<unknown, unknown>;
192
188
 
@@ -231,33 +227,35 @@ export function computeSelfTestPlanDigest(provider: ProviderDefinition): string
231
227
 
232
228
  /**
233
229
  * Fail-closed read-only classification: an operation may self-test only when
234
- * its own metadata marks it read-only (annotations.readOnly or
235
- * toolRouter.riskClass "read") and nothing marks it side-effecting. Unclassified
236
- * operations are refused so the endpoint cannot become a mutation oracle.
230
+ * its authored safety source of truth classifies it as read-only.
237
231
  */
238
232
  export function isSelfTestReadOnlyOperation(operation: OperationDefinition): boolean {
239
- const annotations = operation.annotations;
240
- if (annotations?.readOnly === false) return false;
241
- if (annotations?.destructive === true) return false;
242
- const riskClass = operation.toolRouter?.riskClass;
243
- if (riskClass !== undefined && riskClass !== "read") return false;
244
- return annotations?.readOnly === true || riskClass === "read";
233
+ return operation.riskClass === "read";
245
234
  }
246
235
 
247
236
  /** Binds the self-test executor to a tenant app's /v1 pipeline in-process. */
248
237
  export function createSelfTestInvoke(app: {
249
238
  request: (input: string, requestInit?: RequestInit) => Response | Promise<Response>;
250
239
  }): SelfTestOperationInvoke {
251
- return async ({ operationId, input, connection, requestId }) => {
252
- const response = await app.request(`/v1/${encodeURIComponent(operationId)}`, {
253
- method: "POST",
254
- headers: { "content-type": "application/json" },
255
- body: JSON.stringify({
256
- requestId,
257
- input: input ?? {},
258
- ...(connection ? { connection } : {}),
240
+ return async ({ operationId, input, connection, requestId, signal }) => {
241
+ const responsePromise = Promise.resolve(
242
+ app.request(`/v1/${encodeURIComponent(operationId)}`, {
243
+ method: "POST",
244
+ headers: { "content-type": "application/json" },
245
+ body: JSON.stringify({
246
+ requestId,
247
+ input: input ?? {},
248
+ ...(connection ? { connection } : {}),
249
+ }),
250
+ ...(signal ? { signal } : {}),
259
251
  }),
260
- });
252
+ );
253
+ const response = await responsePromise;
254
+ if (signal?.aborted) {
255
+ await cancelSelfTestResponse(response);
256
+ signal.throwIfAborted();
257
+ }
258
+ // An abort after body consumption starts may let response.text() finish.
261
259
  const text = await response.text();
262
260
  let body: unknown = text;
263
261
  try {
@@ -277,22 +275,75 @@ export function createSelfTestInvoke(app: {
277
275
  };
278
276
  }
279
277
 
278
+ async function cancelSelfTestResponse(response: Response): Promise<void> {
279
+ await response.body?.cancel().catch(() => undefined);
280
+ }
281
+
282
+ function selfTestAbortReason(reason: unknown, sensitiveValues: readonly string[]): string {
283
+ const text =
284
+ reason instanceof Error
285
+ ? reason.message || reason.name
286
+ : reason === undefined
287
+ ? "aborted"
288
+ : String(reason);
289
+ return redactSelfTestText(text, sensitiveValues);
290
+ }
291
+
292
+ function logSelfTestCancellation(
293
+ provider: ProviderDefinition,
294
+ options: SelfTestAppOptions,
295
+ requestId: string,
296
+ selected: SelectedCase,
297
+ signal: AbortSignal,
298
+ sensitiveValues: readonly string[],
299
+ ): void {
300
+ const event: SelfTestCancellationLogEvent = {
301
+ level: "info",
302
+ event: "self_test_run_cancelled",
303
+ providerId: provider.id,
304
+ requestId,
305
+ operationId: selected.operationId,
306
+ caseName: selected.healthCase.name,
307
+ reason: selfTestAbortReason(signal.reason, sensitiveValues),
308
+ };
309
+ if (options.logger) {
310
+ options.logger(event);
311
+ return;
312
+ }
313
+ console.log(JSON.stringify(event));
314
+ }
315
+
280
316
  /** Binds the self-test auth-flow driver to a tenant app's /auth pipeline in-process. */
281
317
  export function createSelfTestAuthFlowInvoke(app: {
282
318
  request: (input: string, requestInit?: RequestInit) => Response | Promise<Response>;
283
319
  }): SelfTestAuthFlowInvoke {
284
- return async ({ route, requestId, flowId, connectionId, externalRef, input, context }) => {
320
+ return async ({
321
+ route,
322
+ requestId,
323
+ flowId,
324
+ connectionId,
325
+ externalRef,
326
+ input,
327
+ context,
328
+ engine,
329
+ signal,
330
+ }) => {
285
331
  const response = await app.request(`/auth/${route}`, {
286
332
  method: "POST",
287
333
  headers: { "content-type": "application/json" },
288
334
  body: JSON.stringify({
289
335
  requestId,
290
336
  flowId,
337
+ // Engine ceremony leases are scoped to a tenant; the self-test has no
338
+ // customer tenant, so it presents a fixed one that never collides.
339
+ tenantId: "self-test",
291
340
  ...(connectionId ? { connectionId } : {}),
292
341
  ...(externalRef ? { externalRef } : {}),
293
342
  ...(input ? { input } : {}),
294
343
  ...(context ? { context } : {}),
344
+ ...(engine ? { engine } : {}),
295
345
  }),
346
+ ...(signal ? { signal } : {}),
296
347
  });
297
348
  const text = await response.text();
298
349
  let body: unknown = text;
@@ -312,17 +363,32 @@ class SelfTestCaseTimeoutError extends Error {
312
363
  }
313
364
  }
314
365
 
315
- async function withCaseTimeout<T>(run: () => Promise<T>, timeoutMs: number): Promise<T> {
366
+ async function withCaseTimeout<T>(
367
+ run: () => Promise<T>,
368
+ timeoutMs: number,
369
+ controller: AbortController,
370
+ ): Promise<T> {
316
371
  let timer: ReturnType<typeof setTimeout> | undefined;
372
+ let onAbort: (() => void) | undefined;
317
373
  try {
318
374
  return await Promise.race([
319
375
  run(),
320
376
  new Promise<never>((_, reject) => {
321
- timer = setTimeout(() => reject(new SelfTestCaseTimeoutError(timeoutMs)), timeoutMs);
377
+ timer = setTimeout(() => {
378
+ const error = new SelfTestCaseTimeoutError(timeoutMs);
379
+ controller.abort(error);
380
+ reject(error);
381
+ }, timeoutMs);
382
+ }),
383
+ new Promise<never>((_, reject) => {
384
+ onAbort = () => reject(controller.signal.reason);
385
+ controller.signal.addEventListener("abort", onAbort, { once: true });
386
+ if (controller.signal.aborted) onAbort();
322
387
  }),
323
388
  ]);
324
389
  } finally {
325
390
  if (timer !== undefined) clearTimeout(timer);
391
+ if (onAbort) controller.signal.removeEventListener("abort", onAbort);
326
392
  }
327
393
  }
328
394
 
@@ -471,6 +537,7 @@ type ParsedAuthFlowTurn =
471
537
  ok: true;
472
538
  turn: { kind: string; data?: unknown; expectedInput?: unknown };
473
539
  contextPatch?: Record<string, unknown>;
540
+ engine?: { egressLease: string };
474
541
  }
475
542
  | { ok: false; code: string; message: string; httpStatus: number };
476
543
 
@@ -499,6 +566,7 @@ function parseAuthFlowResponse(result: { status: number; body: unknown }): Parse
499
566
  };
500
567
  }
501
568
  const contextPatch = objectProperty(result.body, "contextPatch");
569
+ const egressLease = objectProperty(objectProperty(result.body, "engine"), "egressLease");
502
570
  return {
503
571
  ok: true,
504
572
  turn: {
@@ -509,6 +577,7 @@ function parseAuthFlowResponse(result: { status: number; body: unknown }): Parse
509
577
  ...(contextPatch && typeof contextPatch === "object" && !Array.isArray(contextPatch)
510
578
  ? { contextPatch: contextPatch as Record<string, unknown> }
511
579
  : {}),
580
+ ...(typeof egressLease === "string" && egressLease ? { engine: { egressLease } } : {}),
512
581
  };
513
582
  }
514
583
 
@@ -595,6 +664,7 @@ async function materializeFlowCredential(
595
664
  isAbandoned?: () => boolean;
596
665
  connectionId?: string;
597
666
  externalRef?: string;
667
+ signal?: AbortSignal;
598
668
  } = {},
599
669
  ): Promise<
600
670
  | { credential: Record<string, string> }
@@ -621,6 +691,7 @@ async function materializeFlowCredential(
621
691
  flowId,
622
692
  ...(options.connectionId ? { connectionId: options.connectionId } : {}),
623
693
  ...(options.externalRef ? { externalRef: options.externalRef } : {}),
694
+ ...(options.signal ? { signal: options.signal } : {}),
624
695
  }),
625
696
  );
626
697
  if (!started.ok) {
@@ -696,6 +767,10 @@ async function materializeFlowCredential(
696
767
  ...(options.externalRef ? { externalRef: options.externalRef } : {}),
697
768
  input: submitInputs,
698
769
  ...(Object.keys(flowContext).length > 0 ? { context: flowContext } : {}),
770
+ // The ceremony egress lease is engine state, not flow context: carry it the
771
+ // way the gateway does so the continue turn stays on the start turn's egress.
772
+ ...(started.engine ? { engine: started.engine } : {}),
773
+ ...(options.signal ? { signal: options.signal } : {}),
699
774
  }),
700
775
  );
701
776
  if (!continued.ok) {
@@ -756,7 +831,7 @@ async function resolveSelfTestConnection(
756
831
  execution: SelfTestExecutionContext,
757
832
  operationId: string,
758
833
  suite: AnyHealthCheckSuite,
759
- options: { forceLogin?: boolean; isAbandoned?: () => boolean } = {},
834
+ options: { forceLogin?: boolean; isAbandoned?: () => boolean; signal?: AbortSignal } = {},
760
835
  ): Promise<SelfTestConnectionResolution> {
761
836
  if (!suite.requiresConnection) return { kind: "connection" };
762
837
  const inputs = execution.credentials ?? {};
@@ -861,6 +936,7 @@ async function resolveSelfTestConnection(
861
936
  ...(options.isAbandoned !== undefined ? { isAbandoned: options.isAbandoned } : {}),
862
937
  connectionId,
863
938
  externalRef: `${execution.provider.id}-${operationId}-self-test`,
939
+ ...(options.signal ? { signal: options.signal } : {}),
864
940
  });
865
941
  if (!("credential" in materialized)) {
866
942
  // Only the multi-turn SKIP is negative-cached. Flow ERRORS
@@ -879,10 +955,9 @@ async function resolveSelfTestConnection(
879
955
  }
880
956
  return materialized;
881
957
  }
882
- // A flow that outlived the case deadline still completes here (the timeout
883
- // only races the promise, it cannot cancel it). The case already reported
884
- // self_test_timeout — caching this credential would let the next probe
885
- // reuse a login whose latency just failed the case, hiding the failure.
958
+ // Abort is cooperative: a flow may still complete after the case deadline
959
+ // if provider code ignores the signal. Never cache that late credential or
960
+ // let the next probe hide the timed-out login.
886
961
  if (options.isAbandoned?.() === true) {
887
962
  return {
888
963
  kind: "flow_error",
@@ -913,6 +988,7 @@ async function executeSelfTestCase(
913
988
  operationId: string,
914
989
  suite: AnyHealthCheckSuite,
915
990
  healthCase: AnyHealthCheckCase,
991
+ caseController: AbortController,
916
992
  ): Promise<SelfTestCaseResult> {
917
993
  const { provider, invoke } = execution;
918
994
  // execution.sensitiveValues may grow while the case runs (flow-issued
@@ -926,6 +1002,8 @@ async function executeSelfTestCase(
926
1002
  const caseDeadlineAtMs = performance.now() + timeoutMs;
927
1003
  const remainingCaseTimeoutMs = () =>
928
1004
  Math.max(1, Math.ceil(caseDeadlineAtMs - performance.now()));
1005
+ const runWithCaseTimeout = <T>(run: () => Promise<T>, remainingMs: number) =>
1006
+ withCaseTimeout(run, remainingMs, caseController);
929
1007
 
930
1008
  const beginCase = () => {
931
1009
  const startedAt = new Date().toISOString();
@@ -959,16 +1037,17 @@ async function executeSelfTestCase(
959
1037
  }
960
1038
 
961
1039
  const resolveConnection = async (forceLogin: boolean): Promise<SelfTestConnectionResolution> => {
962
- // The timeout only races the flow promise — it cannot cancel it. Once
963
- // the deadline fires, the still-running resolution is marked abandoned
964
- // so its late completion cannot write the session cache.
1040
+ // The deadline aborts the in-process flow request. Keep the abandonment
1041
+ // guard as a backstop for provider code that ignores cancellation so a
1042
+ // late completion still cannot write the session cache.
965
1043
  let abandoned = false;
966
1044
  try {
967
- return await withCaseTimeout(
1045
+ return await runWithCaseTimeout(
968
1046
  () =>
969
1047
  resolveSelfTestConnection(execution, operationId, suite, {
970
1048
  forceLogin,
971
1049
  isAbandoned: () => abandoned,
1050
+ signal: caseController.signal,
972
1051
  }),
973
1052
  remainingCaseTimeoutMs(),
974
1053
  );
@@ -1012,7 +1091,12 @@ async function executeSelfTestCase(
1012
1091
  // operation attempt, or a slow login reads as a fast healthy case.
1013
1092
  const { startedAtMs, finish } = caseScope;
1014
1093
  try {
1015
- return await withCaseTimeout(async () => {
1094
+ return await runWithCaseTimeout(async () => {
1095
+ if (healthCase.assertions === undefined) {
1096
+ throw new Error(
1097
+ `Self-test cannot execute declarative health-check case "${healthCase.name}"; run its scenario through the health monitor.`,
1098
+ );
1099
+ }
1016
1100
  const resolvedInput = resolveHealthCheckInputDateTokens(healthCase.input);
1017
1101
  const preparedInput = healthCase.prepareInput
1018
1102
  ? await healthCase.prepareInput({
@@ -1033,6 +1117,7 @@ async function executeSelfTestCase(
1033
1117
  input: gatewayInput,
1034
1118
  connection,
1035
1119
  requestId: `${execution.requestId}-prepare-${randomUUID()}`,
1120
+ signal: caseController.signal,
1036
1121
  });
1037
1122
  if (executed.status === 401 || executed.status === 403) {
1038
1123
  prepareAuthStatus = executed.status;
@@ -1053,6 +1138,7 @@ async function executeSelfTestCase(
1053
1138
  input: preparedInput,
1054
1139
  connection,
1055
1140
  requestId: `${execution.requestId}-${randomUUID()}`,
1141
+ signal: caseController.signal,
1056
1142
  });
1057
1143
  const durationMs = performance.now() - startedAtMs;
1058
1144
 
@@ -1383,47 +1469,77 @@ export function createSelfTestApp(provider: ProviderDefinition, options: SelfTes
1383
1469
  };
1384
1470
  const deadline = performance.now() + requestBudgetMs;
1385
1471
  const results: SelfTestCaseResult[] = [];
1472
+ const runSignal = c.req.raw.signal;
1473
+ let interruptedCase: SelectedCase | undefined;
1386
1474
  // Sequential execution (parallelism 1): self-tests run on serving pods
1387
1475
  // and must never compete with themselves for upstream quota.
1388
1476
  for (const selected of selection.cases) {
1389
- if (performance.now() >= deadline) {
1390
- const now = new Date().toISOString();
1391
- results.push({
1392
- operationId: selected.operationId,
1393
- caseName: selected.healthCase.name,
1394
- status: "skipped",
1395
- label: selected.healthCase.name,
1396
- responseTimeMs: 0,
1397
- skipReason: "budget_exhausted",
1398
- startedAt: now,
1399
- finishedAt: now,
1400
- });
1401
- continue;
1402
- }
1403
- if (!isSelfTestReadOnlyOperation(selected.operation)) {
1404
- const now = new Date().toISOString();
1405
- results.push({
1406
- operationId: selected.operationId,
1407
- caseName: selected.healthCase.name,
1408
- status: "error",
1409
- label: selected.healthCase.name,
1410
- responseTimeMs: 0,
1411
- error: {
1412
- code: "operation_not_read_only",
1413
- message: `Operation "${selected.operationId}" is not classified read-only; self-test refuses to execute it.`,
1414
- },
1415
- startedAt: now,
1416
- finishedAt: now,
1417
- });
1418
- continue;
1477
+ const caseController = new AbortController();
1478
+ const abortFromRun = () => caseController.abort(runSignal.reason);
1479
+ runSignal.addEventListener("abort", abortFromRun, { once: true });
1480
+ if (runSignal.aborted) abortFromRun();
1481
+ try {
1482
+ if (runSignal.aborted) {
1483
+ interruptedCase = selected;
1484
+ break;
1485
+ }
1486
+ if (performance.now() >= deadline) {
1487
+ const now = new Date().toISOString();
1488
+ results.push({
1489
+ operationId: selected.operationId,
1490
+ caseName: selected.healthCase.name,
1491
+ status: "skipped",
1492
+ label: selected.healthCase.name,
1493
+ responseTimeMs: 0,
1494
+ skipReason: "budget_exhausted",
1495
+ startedAt: now,
1496
+ finishedAt: now,
1497
+ });
1498
+ continue;
1499
+ }
1500
+ if (!isSelfTestReadOnlyOperation(selected.operation)) {
1501
+ const now = new Date().toISOString();
1502
+ results.push({
1503
+ operationId: selected.operationId,
1504
+ caseName: selected.healthCase.name,
1505
+ status: "error",
1506
+ label: selected.healthCase.name,
1507
+ responseTimeMs: 0,
1508
+ error: {
1509
+ code: "operation_not_read_only",
1510
+ message: `Operation "${selected.operationId}" is not classified read-only; self-test refuses to execute it.`,
1511
+ },
1512
+ startedAt: now,
1513
+ finishedAt: now,
1514
+ });
1515
+ continue;
1516
+ }
1517
+ results.push(
1518
+ await executeSelfTestCase(
1519
+ execution,
1520
+ selected.operationId,
1521
+ selected.suite,
1522
+ selected.healthCase,
1523
+ caseController,
1524
+ ),
1525
+ );
1526
+ if (runSignal.aborted) {
1527
+ interruptedCase = selected;
1528
+ break;
1529
+ }
1530
+ } finally {
1531
+ runSignal.removeEventListener("abort", abortFromRun);
1532
+ caseController.abort();
1419
1533
  }
1420
- results.push(
1421
- await executeSelfTestCase(
1422
- execution,
1423
- selected.operationId,
1424
- selected.suite,
1425
- selected.healthCase,
1426
- ),
1534
+ }
1535
+ if (interruptedCase) {
1536
+ logSelfTestCancellation(
1537
+ provider,
1538
+ options,
1539
+ request.requestId,
1540
+ interruptedCase,
1541
+ runSignal,
1542
+ execution.sensitiveValues,
1427
1543
  );
1428
1544
  }
1429
1545
  const singleCase = request.operationId !== undefined && request.caseName !== undefined;