@apifuse/provider-sdk 2.2.0-beta.5 → 2.2.0-beta.50

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 (365) hide show
  1. package/AUTHORING.md +537 -33
  2. package/CHANGELOG.md +201 -1
  3. package/README.md +83 -22
  4. package/SUBMISSION.md +2 -2
  5. package/bin/apifuse-check.ts +165 -11
  6. package/bin/apifuse-dev.ts +57 -13
  7. package/bin/apifuse-migrate-operation-declaration.ts +55 -0
  8. package/bin/apifuse-migrate-shape.ts +202 -0
  9. package/bin/apifuse-pack-check.ts +22 -2
  10. package/bin/apifuse-pack-smoke.ts +57 -2
  11. package/bin/apifuse-pack-types.ts +357 -38
  12. package/bin/apifuse-perf.ts +14 -13
  13. package/bin/apifuse-record.ts +709 -72
  14. package/bin/apifuse-submit-check.ts +2344 -324
  15. package/bin/apifuse-sync-assets.ts +117 -0
  16. package/bin/submit-check-delimited-text.ts +50 -0
  17. package/dist/auth-turn/index.d.ts +3 -3
  18. package/dist/auth-turn/index.js +1 -1
  19. package/dist/auth.d.ts +14 -0
  20. package/dist/auth.js +67 -0
  21. package/dist/ceremonies/index.d.ts +16 -0
  22. package/dist/ceremonies/index.js +141 -36
  23. package/dist/cli/commands.d.ts +1 -1
  24. package/dist/cli/commands.js +27 -0
  25. package/dist/cli/create.d.ts +4 -1
  26. package/dist/cli/create.js +42 -37
  27. package/dist/cli/migrate-operation-declaration.d.ts +59 -0
  28. package/dist/cli/migrate-operation-declaration.js +1178 -0
  29. package/dist/cli/migrate-operation-shape.d.ts +44 -0
  30. package/dist/cli/migrate-operation-shape.js +113 -0
  31. package/dist/cli/migrate-provider-shape.d.ts +52 -0
  32. package/dist/cli/migrate-provider-shape.js +578 -0
  33. package/dist/cli/prompt-assets.d.ts +80 -0
  34. package/dist/cli/prompt-assets.js +743 -0
  35. package/dist/cli/templates/provider/AGENTS.md.tpl +17 -8
  36. package/dist/cli/templates/provider/Dockerfile.tpl +1 -1
  37. package/dist/cli/templates/provider/README.md.tpl +5 -5
  38. package/dist/cli/templates/provider/index.ts.tpl +6 -3
  39. package/dist/cli/templates/provider/operations/ping.ts.tpl +4 -1
  40. package/dist/cli/templates/provider/provider.json.tpl +6 -0
  41. package/dist/config/loader.d.ts +179 -16
  42. package/dist/config/loader.js +435 -127
  43. package/dist/contract-serialization.js +4 -8
  44. package/dist/contract-types.d.ts +12 -5
  45. package/dist/contract.js +24 -10
  46. package/dist/declaration-validation.d.ts +33 -0
  47. package/dist/declaration-validation.js +266 -0
  48. package/dist/define.d.ts +66 -29
  49. package/dist/define.js +778 -69
  50. package/dist/dev.d.ts +3 -0
  51. package/dist/dev.js +1 -1
  52. package/dist/engine.d.ts +78 -0
  53. package/dist/engine.js +133 -0
  54. package/dist/error-observability.d.ts +7 -0
  55. package/dist/error-observability.js +61 -0
  56. package/dist/error-resolution.d.ts +4 -0
  57. package/dist/error-resolution.js +122 -0
  58. package/dist/errors.d.ts +33 -0
  59. package/dist/errors.js +40 -0
  60. package/dist/fixture-sanitization.d.ts +28 -0
  61. package/dist/fixture-sanitization.js +227 -0
  62. package/dist/health-scenario.d.ts +1842 -0
  63. package/dist/health-scenario.js +624 -0
  64. package/dist/index.d.ts +21 -10
  65. package/dist/index.js +12 -7
  66. package/dist/lint.d.ts +23 -11
  67. package/dist/lint.js +572 -69
  68. package/dist/native-address.d.ts +43 -0
  69. package/dist/native-address.js +281 -0
  70. package/dist/native-egress-policy.d.ts +31 -0
  71. package/dist/native-egress-policy.js +288 -0
  72. package/dist/observability.d.ts +5 -2
  73. package/dist/observability.js +48 -1
  74. package/dist/provider.d.ts +10 -2
  75. package/dist/provider.js +4 -1
  76. package/dist/runtime/auth-flow.d.ts +5 -1
  77. package/dist/runtime/auth-flow.js +6 -0
  78. package/dist/runtime/browser.d.ts +1 -0
  79. package/dist/runtime/browser.js +492 -49
  80. package/dist/runtime/cache.d.ts +1 -0
  81. package/dist/runtime/cache.js +169 -15
  82. package/dist/runtime/choice-wordlist.d.ts +9 -0
  83. package/dist/runtime/choice-wordlist.js +138 -0
  84. package/dist/runtime/choice.d.ts +13 -1
  85. package/dist/runtime/choice.js +490 -102
  86. package/dist/runtime/chrome149-header-order.d.ts +58 -0
  87. package/dist/runtime/chrome149-header-order.js +289 -0
  88. package/dist/runtime/env.js +12 -0
  89. package/dist/runtime/executor.d.ts +3 -2
  90. package/dist/runtime/executor.js +26 -25
  91. package/dist/runtime/http.d.ts +1 -0
  92. package/dist/runtime/http.js +515 -53
  93. package/dist/runtime/insights.js +2 -2
  94. package/dist/runtime/instrumentation.d.ts +2 -2
  95. package/dist/runtime/instrumentation.js +366 -8
  96. package/dist/runtime/native-network-errors.d.ts +33 -0
  97. package/dist/runtime/native-network-errors.js +69 -0
  98. package/dist/runtime/native-network.d.ts +96 -0
  99. package/dist/runtime/native-network.js +1232 -0
  100. package/dist/runtime/ocr.d.ts +29 -0
  101. package/dist/runtime/ocr.js +440 -0
  102. package/dist/runtime/otlp.d.ts +71 -2
  103. package/dist/runtime/otlp.js +397 -16
  104. package/dist/runtime/proxy-errors.js +6 -2
  105. package/dist/runtime/proxy-nodemaven.d.ts +56 -0
  106. package/dist/runtime/proxy-nodemaven.js +146 -0
  107. package/dist/runtime/proxy-telemetry.d.ts +80 -1
  108. package/dist/runtime/proxy-telemetry.js +154 -47
  109. package/dist/runtime/redirects.d.ts +29 -0
  110. package/dist/runtime/redirects.js +36 -0
  111. package/dist/runtime/redis.d.ts +1 -1
  112. package/dist/runtime/redis.js +4 -2
  113. package/dist/runtime/request-options.d.ts +68 -1
  114. package/dist/runtime/request-options.js +548 -0
  115. package/dist/runtime/resolver-config.d.ts +6 -0
  116. package/dist/runtime/resolver-config.js +6 -0
  117. package/dist/runtime/resolver-public.d.ts +1 -0
  118. package/dist/runtime/resolver-public.js +1 -0
  119. package/dist/runtime/resolver-shared.d.ts +14 -0
  120. package/dist/runtime/resolver-shared.js +12 -0
  121. package/dist/runtime/resolver-vendors/bindings.d.ts +48 -0
  122. package/dist/runtime/resolver-vendors/bindings.js +40 -0
  123. package/dist/runtime/resolver-vendors/browser.d.ts +22 -0
  124. package/dist/runtime/resolver-vendors/browser.js +377 -0
  125. package/dist/runtime/resolver-vendors/capsolver.d.ts +22 -0
  126. package/dist/runtime/resolver-vendors/capsolver.js +531 -0
  127. package/dist/runtime/resolver-vendors/hosts.d.ts +2 -0
  128. package/dist/runtime/resolver-vendors/hosts.js +33 -0
  129. package/dist/runtime/resolver-vendors/twocaptcha.d.ts +24 -0
  130. package/dist/runtime/resolver-vendors/twocaptcha.js +408 -0
  131. package/dist/runtime/resolver-vendors/types.d.ts +94 -0
  132. package/dist/runtime/resolver-vendors/types.js +96 -0
  133. package/dist/runtime/resolver.d.ts +72 -0
  134. package/dist/runtime/resolver.js +771 -0
  135. package/dist/runtime/secrets.d.ts +27 -0
  136. package/dist/runtime/secrets.js +51 -0
  137. package/dist/runtime/state.d.ts +3 -0
  138. package/dist/runtime/state.js +277 -71
  139. package/dist/runtime/stealth-cookies.d.ts +20 -0
  140. package/dist/runtime/stealth-cookies.js +111 -0
  141. package/dist/runtime/stealth.d.ts +41 -5
  142. package/dist/runtime/stealth.js +997 -291
  143. package/dist/runtime/stt.js +1 -12
  144. package/dist/runtime/timeout.d.ts +5 -0
  145. package/dist/runtime/timeout.js +12 -0
  146. package/dist/runtime/trace-config.d.ts +12 -0
  147. package/dist/runtime/trace-config.js +62 -0
  148. package/dist/runtime/trace.d.ts +5 -0
  149. package/dist/runtime/trace.js +43 -10
  150. package/dist/serve.d.ts +1 -1
  151. package/dist/serve.js +1 -1
  152. package/dist/server/error-observability.d.ts +1 -0
  153. package/dist/server/error-observability.js +1 -0
  154. package/dist/server/index.d.ts +5 -2
  155. package/dist/server/index.js +2 -2
  156. package/dist/server/self-test-input-tokens.d.ts +2 -1
  157. package/dist/server/self-test-input-tokens.js +18 -14
  158. package/dist/server/self-test.d.ts +14 -3
  159. package/dist/server/self-test.js +129 -58
  160. package/dist/server/serve-implementation.d.ts +230 -0
  161. package/dist/server/serve-implementation.js +2265 -0
  162. package/dist/server/serve.d.ts +1 -70
  163. package/dist/server/serve.js +1 -1131
  164. package/dist/server/trace-output.d.ts +6 -0
  165. package/dist/server/trace-output.js +79 -0
  166. package/dist/server/types.d.ts +30 -5
  167. package/dist/server/types.js +13 -1
  168. package/dist/stateful/errors.d.ts +19 -0
  169. package/dist/stateful/errors.js +24 -0
  170. package/dist/stateful/http-provider-event-emitter.d.ts +40 -0
  171. package/dist/stateful/http-provider-event-emitter.js +237 -0
  172. package/dist/stateful/http-session-owner-registry.d.ts +44 -0
  173. package/dist/stateful/http-session-owner-registry.js +210 -0
  174. package/dist/stateful/index.d.ts +18 -0
  175. package/dist/stateful/index.js +18 -0
  176. package/dist/stateful/provider-event-delivery-failures.d.ts +32 -0
  177. package/dist/stateful/provider-event-delivery-failures.js +43 -0
  178. package/dist/stateful/provider-event-pipeline-metrics.d.ts +46 -0
  179. package/dist/stateful/provider-event-pipeline-metrics.js +48 -0
  180. package/dist/stateful/provider-event-pipeline.d.ts +50 -0
  181. package/dist/stateful/provider-event-pipeline.js +1 -0
  182. package/dist/stateful/provider-events.d.ts +101 -0
  183. package/dist/stateful/provider-events.js +289 -0
  184. package/dist/stateful/session-key.d.ts +15 -0
  185. package/dist/stateful/session-key.js +86 -0
  186. package/dist/stateful/stateful-provider-adapter-context.d.ts +5 -0
  187. package/dist/stateful/stateful-provider-adapter-context.js +42 -0
  188. package/dist/stateful/stateful-provider-adapter-metrics.d.ts +15 -0
  189. package/dist/stateful/stateful-provider-adapter-metrics.js +21 -0
  190. package/dist/stateful/stateful-provider-adapter.d.ts +98 -0
  191. package/dist/stateful/stateful-provider-adapter.js +287 -0
  192. package/dist/stateful/stateful-provider-observability.d.ts +62 -0
  193. package/dist/stateful/stateful-provider-observability.js +161 -0
  194. package/dist/stateful/stateful-provider-owner-forwarder.d.ts +41 -0
  195. package/dist/stateful/stateful-provider-owner-forwarder.js +215 -0
  196. package/dist/stateful/stateful-provider-runtime-context.d.ts +32 -0
  197. package/dist/stateful/stateful-provider-runtime-context.js +60 -0
  198. package/dist/stateful/stateful-provider-runtime-executor.d.ts +34 -0
  199. package/dist/stateful/stateful-provider-runtime-executor.js +52 -0
  200. package/dist/stateful/stateful-provider-session-routing.d.ts +67 -0
  201. package/dist/stateful/stateful-provider-session-routing.js +345 -0
  202. package/dist/stateful/stateful-provider-session-runtime.d.ts +98 -0
  203. package/dist/stateful/stateful-provider-session-runtime.js +245 -0
  204. package/dist/stateful-signing.d.ts +18 -0
  205. package/dist/stateful-signing.js +27 -0
  206. package/dist/stealth/profiles.d.ts +9 -4
  207. package/dist/stealth/profiles.js +160 -211
  208. package/dist/stream-evidence.d.ts +74 -0
  209. package/dist/stream-evidence.js +785 -0
  210. package/dist/stream.js +7 -1
  211. package/dist/testing/index.d.ts +2 -1
  212. package/dist/testing/index.js +2 -1
  213. package/dist/testing/run.d.ts +32 -2
  214. package/dist/testing/run.js +489 -21
  215. package/dist/trace-sanitization.d.ts +5 -0
  216. package/dist/trace-sanitization.js +45 -0
  217. package/dist/types.d.ts +673 -131
  218. package/dist/types.js +1 -0
  219. package/package.json +45 -5
  220. package/src/auth-turn/index.ts +1 -1
  221. package/src/auth.ts +118 -0
  222. package/src/ceremonies/index.ts +189 -46
  223. package/src/cli/__tests__/fixtures/migrate-operation-declaration/approval-override.ts.txt +6 -0
  224. package/src/cli/__tests__/fixtures/migrate-operation-declaration/codemod-syntax.ts.txt +3 -0
  225. package/src/cli/__tests__/fixtures/migrate-operation-declaration/connection-precedence.ts.txt +10 -0
  226. package/src/cli/__tests__/fixtures/migrate-operation-declaration/docs-conflict.ts.txt +8 -0
  227. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-map.ts.txt +5 -0
  228. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-operation.ts.txt +16 -0
  229. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-map.ts.txt +3 -0
  230. package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoist-all.ts.txt +31 -0
  231. package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoisted-const.ts.txt +11 -0
  232. package/src/cli/__tests__/fixtures/migrate-operation-declaration/imported-spread.ts.txt +11 -0
  233. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-map.ts.txt +11 -0
  234. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-cast-tail.ts.txt +21 -0
  235. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-ekitan.ts.txt +11 -0
  236. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-override.ts.txt +14 -0
  237. package/src/cli/__tests__/fixtures/migrate-operation-declaration/missing-english-locale.ts.txt +7 -0
  238. package/src/cli/__tests__/fixtures/migrate-operation-declaration/no-safety.ts.txt +6 -0
  239. package/src/cli/__tests__/fixtures/migrate-operation-declaration/non-literal.ts.txt +7 -0
  240. package/src/cli/__tests__/fixtures/migrate-operation-declaration/redundant-approval.ts.txt +6 -0
  241. package/src/cli/__tests__/fixtures/migrate-operation-declaration/safety-conflict.ts.txt +7 -0
  242. package/src/cli/__tests__/fixtures/migrate-operation-declaration/stream.ts.txt +7 -0
  243. package/src/cli/__tests__/fixtures/migrate-operation-declaration/tool-router-spread.ts.txt +15 -0
  244. package/src/cli/__tests__/fixtures/migrate-operation-declaration/unparseable.ts.txt +4 -0
  245. package/src/cli/__tests__/fixtures/migrate-operation-declaration/verbatim-template.ts.txt +12 -0
  246. package/src/cli/commands.ts +33 -0
  247. package/src/cli/create.ts +50 -37
  248. package/src/cli/migrate-operation-declaration.ts +1654 -0
  249. package/src/cli/migrate-operation-shape.ts +184 -0
  250. package/src/cli/migrate-provider-shape.ts +772 -0
  251. package/src/cli/prompt-assets.ts +865 -0
  252. package/src/cli/templates/provider/AGENTS.md.tpl +17 -8
  253. package/src/cli/templates/provider/Dockerfile.tpl +1 -1
  254. package/src/cli/templates/provider/README.md.tpl +5 -5
  255. package/src/cli/templates/provider/index.ts.tpl +6 -3
  256. package/src/cli/templates/provider/operations/ping.ts.tpl +4 -1
  257. package/src/cli/templates/provider/provider.json.tpl +6 -0
  258. package/src/config/loader.ts +690 -163
  259. package/src/contract-serialization.ts +5 -7
  260. package/src/contract-types.ts +12 -5
  261. package/src/contract.ts +24 -10
  262. package/src/declaration-validation.ts +330 -0
  263. package/src/define.ts +1048 -131
  264. package/src/dev.ts +4 -1
  265. package/src/engine.ts +279 -0
  266. package/src/error-observability.ts +64 -0
  267. package/src/error-resolution.ts +127 -0
  268. package/src/errors.ts +68 -0
  269. package/src/fixture-sanitization.ts +264 -0
  270. package/src/health-scenario.ts +875 -0
  271. package/src/index.ts +220 -13
  272. package/src/lint.ts +698 -90
  273. package/src/native-address.ts +340 -0
  274. package/src/native-egress-policy.ts +358 -0
  275. package/src/observability.ts +51 -1
  276. package/src/provider.ts +161 -3
  277. package/src/runtime/auth-flow.ts +12 -0
  278. package/src/runtime/browser.ts +661 -63
  279. package/src/runtime/cache.ts +189 -14
  280. package/src/runtime/choice-wordlist.ts +145 -0
  281. package/src/runtime/choice.ts +631 -120
  282. package/src/runtime/chrome149-header-order.ts +330 -0
  283. package/src/runtime/env.ts +13 -0
  284. package/src/runtime/executor.ts +43 -31
  285. package/src/runtime/http.ts +641 -61
  286. package/src/runtime/insights.ts +2 -2
  287. package/src/runtime/instrumentation.ts +520 -15
  288. package/src/runtime/native-network-errors.ts +99 -0
  289. package/src/runtime/native-network.ts +1605 -0
  290. package/src/runtime/ocr.ts +523 -0
  291. package/src/runtime/otlp.ts +467 -21
  292. package/src/runtime/proxy-errors.ts +12 -4
  293. package/src/runtime/proxy-nodemaven.ts +221 -0
  294. package/src/runtime/proxy-telemetry.ts +244 -75
  295. package/src/runtime/redirects.ts +66 -0
  296. package/src/runtime/redis.ts +7 -2
  297. package/src/runtime/request-options.ts +680 -1
  298. package/src/runtime/resolver-config.ts +6 -0
  299. package/src/runtime/resolver-public.ts +23 -0
  300. package/src/runtime/resolver-shared.ts +33 -0
  301. package/src/runtime/resolver-vendors/bindings.ts +56 -0
  302. package/src/runtime/resolver-vendors/browser.ts +533 -0
  303. package/src/runtime/resolver-vendors/capsolver.ts +707 -0
  304. package/src/runtime/resolver-vendors/hosts.ts +38 -0
  305. package/src/runtime/resolver-vendors/twocaptcha.ts +540 -0
  306. package/src/runtime/resolver-vendors/types.ts +212 -0
  307. package/src/runtime/resolver.ts +1157 -0
  308. package/src/runtime/secrets.ts +64 -0
  309. package/src/runtime/state.ts +394 -77
  310. package/src/runtime/stealth-cookies.ts +132 -0
  311. package/src/runtime/stealth.ts +1280 -336
  312. package/src/runtime/stt.ts +1 -19
  313. package/src/runtime/timeout.ts +18 -0
  314. package/src/runtime/trace-config.ts +78 -0
  315. package/src/runtime/trace.ts +57 -17
  316. package/src/serve.ts +6 -1
  317. package/src/server/error-observability.ts +1 -0
  318. package/src/server/index.ts +34 -2
  319. package/src/server/self-test-input-tokens.ts +29 -14
  320. package/src/server/self-test.ts +191 -68
  321. package/src/server/serve-implementation.ts +3378 -0
  322. package/src/server/serve.ts +1 -1632
  323. package/src/server/trace-output.ts +129 -0
  324. package/src/server/types.ts +13 -1
  325. package/src/stateful/README.md +146 -0
  326. package/src/stateful/errors.ts +35 -0
  327. package/src/stateful/http-provider-event-emitter.ts +314 -0
  328. package/src/stateful/http-session-owner-registry.ts +306 -0
  329. package/src/stateful/index.ts +18 -0
  330. package/src/stateful/provider-event-delivery-failures.ts +80 -0
  331. package/src/stateful/provider-event-pipeline-metrics.ts +95 -0
  332. package/src/stateful/provider-event-pipeline.ts +61 -0
  333. package/src/stateful/provider-events.ts +462 -0
  334. package/src/stateful/session-key.ts +111 -0
  335. package/src/stateful/stateful-provider-adapter-context.ts +59 -0
  336. package/src/stateful/stateful-provider-adapter-metrics.ts +48 -0
  337. package/src/stateful/stateful-provider-adapter.ts +562 -0
  338. package/src/stateful/stateful-provider-observability.ts +261 -0
  339. package/src/stateful/stateful-provider-owner-forwarder.ts +287 -0
  340. package/src/stateful/stateful-provider-runtime-context.ts +92 -0
  341. package/src/stateful/stateful-provider-runtime-executor.ts +96 -0
  342. package/src/stateful/stateful-provider-session-routing.ts +546 -0
  343. package/src/stateful/stateful-provider-session-runtime.ts +403 -0
  344. package/src/stateful-signing.ts +46 -0
  345. package/src/stealth/profiles.ts +202 -231
  346. package/src/stream-evidence.ts +988 -0
  347. package/src/stream.ts +8 -1
  348. package/src/testing/index.ts +10 -1
  349. package/src/testing/run.ts +658 -15
  350. package/src/trace-sanitization.ts +63 -0
  351. package/src/types.ts +788 -174
  352. package/dist/cli/templates/provider/CLAUDE.md.tpl +0 -1
  353. package/src/cli/templates/provider/CLAUDE.md.tpl +0 -1
  354. /package/dist/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
  355. /package/dist/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
  356. /package/dist/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
  357. /package/dist/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
  358. /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
  359. /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
  360. /package/src/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
  361. /package/src/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
  362. /package/src/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
  363. /package/src/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
  364. /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
  365. /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
package/AUTHORING.md CHANGED
@@ -73,38 +73,189 @@ payment state tokens in the platform monorepo.
73
73
 
74
74
  ### Description template
75
75
 
76
- Every operation `description` MUST be at least 150 characters and follow this structure:
76
+ Every operation declares a `descriptionKey`. Its English locale value should
77
+ follow this structure:
77
78
 
78
79
  ```
79
80
  <What the tool does in one sentence>. Use when <specific scenarios>. Do NOT use for <counter-scenarios; point to alternatives>. Returns <key output fields>. <Important caveats: rate limits, auth, freshness>.
80
81
  ```
81
82
 
82
- Example:
83
+ Example declaration and locale entry:
83
84
  ```ts
84
- description:
85
- "Retrieves KMA ultra-short-term weather observation for a given grid coordinate in South Korea, " +
86
- "including temperature, humidity, wind speed, precipitation, and sky condition. " +
87
- "Use when the user asks about current or hourly weather at a specific Korean location. " +
88
- "Do NOT use for forecasts beyond 2 days — use kma_mid_forecast instead. " +
89
- "Returns hourly data in KST timezone; null values indicate data unavailable. " +
90
- "Rate-limited to 1000 calls/day on the free tier.",
85
+ descriptionKey: "operations.realtimeWeather.description",
86
+ ```
87
+
88
+ ```json
89
+ {
90
+ "operations": {
91
+ "realtimeWeather": {
92
+ "description": "Retrieves KMA ultra-short-term weather observations for a South Korean grid coordinate. Use when the user asks about current or hourly weather. Do NOT use for forecasts beyond two days; use the mid-range forecast operation instead. Returns hourly KST data; null values mean unavailable data."
93
+ }
94
+ }
95
+ }
91
96
  ```
92
97
 
93
98
  ### Language policy
94
99
 
95
- - **Structural text**: English (operation `description`, Zod `.describe()`, `whenToUse`, `whenNotToUse`, `derivations`, `inputExamples.scenario/rationale`).
96
- - **Values only**: native language (fixtures payloads, `inputExamples[].input` values like "대방동", "KRW-BTC", entity catalog entries).
100
+ - **Structural text**: locale keys (`descriptionKey`, the other `*Key`/`*Keys`
101
+ fields, schema `.describeKey()`, and `examples[].scenarioKey`/`rationaleKey`).
102
+ - **Values only**: native language (fixtures payloads and `examples[].input`
103
+ values like "대방동", "KRW-BTC", entity catalog entries).
97
104
 
98
105
  ### Required per operation
99
106
 
100
- - `description` — 150+ chars English (error-level rule)
101
- - Every Zod field in input AND output has `.describe()` including nested objects + array items (error-level rule)
107
+ - `riskClass` — authored as `read`, `write`, `destructive`, or `external-send`
108
+ - `descriptionKey` backed by every required provider locale catalog
109
+ - `connectionMode` — explicit for `credentials`, `oauth2`, and `oauth2_proxied` providers
110
+ - Every Zod field in input AND output has `.describeKey()` including nested objects + array items (error-level rule)
102
111
  - `fixtures.request` + `fixtures.response` both present (error-level rule)
103
112
  - Exactly one of `healthCheck`, `healthCheckUnsupported`, or `healthJourneys[].coversOperations` coverage per operation. Prefer `healthCheck` for safe read-only upstream probes; use `healthCheckUnsupported` only with a specific reason for destructive, paid, credential-sensitive, flaky, or otherwise unsafe probes. Use a provider-level health journey when a destructive or credential-sensitive flow can be proven safely only as a multi-step boundary test, such as stopping at a payment WebView URL.
104
113
 
114
+ ### Capability declarations
115
+
116
+ Declare each capability used by provider operations. Capabilities without
117
+ configuration use a bare object, for example `http: {}`, `choice: {}`, or
118
+ `cache: {}`. `trace` is ambient and must not be declared: every operation
119
+ context receives it. `allowedHosts`, `proxy`, `secrets`, and `context` declare
120
+ policy or metadata only; they do not create context members and are not
121
+ capability bindings.
122
+
123
+ Declare `runtimeTarget: "vanilla"` for portable provider business logic. Use
124
+ `runtimeTarget: "engine"` only for an approved session-bearing provider that
125
+ must remain engine-resident. A vanilla target cannot declare `native`.
126
+
127
+ Proxy vendor application keys, usernames, and passwords are engine-owned. Do
128
+ not list `APIFUSE__PROXY__SMARTPROXY_APP_KEY`,
129
+ `APIFUSE__PROXY__NODEMAVEN_USERNAME`, or
130
+ `APIFUSE__PROXY__NODEMAVEN_PASSWORD` in provider `secrets`; `proxy` contains
131
+ policy intent only.
132
+
105
133
  ### Factored operations
106
134
 
107
- Use `defineOperation()` when an operation is large enough to live beside helper functions or in a separate module. It preserves the same type inference as inline `defineProvider()` operations and can be placed directly in the provider `operations` map. `defineProvider()` accepts Zod and Standard Schema v1-compatible schemas. If config validation fails, the SDK names the field to fix, for example `runtime`, `auth.mode`, `operations.<id>.handler`, or `operations.<id>.fixtures.response`.
135
+ `defineProvider(declaration)` returns the builder that accepts `operations`, so
136
+ inline handlers are typed only after capability declarations are fixed. Export
137
+ one declaration-derived context alias from the provider entry point:
138
+
139
+ ```ts
140
+ import {
141
+ defineProvider,
142
+ type ProviderContext,
143
+ type ProviderDeclaration,
144
+ } from "@apifuse/provider-sdk/provider";
145
+
146
+ const declaration = {
147
+ // ...id, version, runtime, meta
148
+ http: {},
149
+ } as const satisfies ProviderDeclaration;
150
+
151
+ export type Ctx = ProviderContext<typeof declaration>;
152
+ const buildProvider = defineProvider(declaration);
153
+ ```
154
+
155
+ Separate operation files need one provider-local type import and no generic
156
+ handler signature:
157
+
158
+ ```ts
159
+ import { defineOperation } from "@apifuse/provider-sdk/provider";
160
+ import type { Ctx } from "../index.js";
161
+
162
+ export const search = defineOperation<Ctx>()({
163
+ // ...input, output, fixtures, health check
164
+ async handler(ctx, input) {
165
+ return fetchSearch(ctx.http, input);
166
+ },
167
+ });
168
+ ```
169
+
170
+ `ProviderContextOf<typeof buildProvider>` remains an equivalent convenience
171
+ alias. Helpers should accept the one SDK client they use rather than the
172
+ provider context. Zod and Standard Schema v1 schemas retain input/output
173
+ inference. Invalid configs name the offending field, such as `auth.mode` or
174
+ `operations.<id>.fixtures.response`.
175
+
176
+ ### Replay-safe fixtures
177
+
178
+ Keep public operation schemas strict: date fields should accept absolute dates,
179
+ not relative tokens. Inside `fixtures.request` only, the SDK resolves `+Nd` and
180
+ `+Nd:YYYYMMDD` (1–365 days ahead) before import-time schema validation and
181
+ stores the resolved request in provider metadata. Health-check case inputs use
182
+ the same resolver when a probe runs. The default calendar is **KST**, including
183
+ the 15:00–23:59 UTC window when KST is already on the next day.
184
+
185
+ `fixtures.recordedAt` is the KST `YYYY-MM-DD` date when the response evidence
186
+ was captured. It must be a real, non-future calendar date. Response date fields
187
+ are expected to align with `recordedAt`, not with the newly resolved request;
188
+ this permits stable recorded evidence alongside a replay-safe request.
189
+
190
+ ```ts
191
+ const FlightInput = z.object({
192
+ departureDate: z.string().date(), // public calls remain absolute-date only
193
+ });
194
+
195
+ const searchFlights = {
196
+ input: FlightInput,
197
+ output: FlightOutput,
198
+ async handler(ctx, input) {
199
+ return fetchAndNormalizeFlights(ctx, input);
200
+ },
201
+ fixtures: {
202
+ request: { departureDate: "+45d" },
203
+ response: recordedFlightResponse, // dates reflect the capture below
204
+ recordedAt: "2026-07-15",
205
+ },
206
+ healthCheckUnsupported: { reason: "Upstream search is cost-bearing." },
207
+ };
208
+ ```
209
+
210
+ For code that explicitly calls the shared resolver, omit the third argument to
211
+ use KST or pass `"UTC"` deliberately:
212
+
213
+ ```ts
214
+ import { resolveHealthCheckInputDateTokens } from "@apifuse/provider-sdk/server";
215
+
216
+ const kstInput = resolveHealthCheckInputDateTokens({ date: "+45d" });
217
+ const utcInput = resolveHealthCheckInputDateTokens({ date: "+45d" }, new Date(), "UTC");
218
+ ```
219
+
220
+ Do not re-resolve a health assertion's dates in UTC when its case input used the
221
+ default KST calendar.
222
+
223
+ ### Real-handler E2E in standard tests
224
+
225
+ `runStandardTests(provider)` validates declarations and fixtures but reports a
226
+ per-operation warning because it has no handler E2E coverage. Opt in with an
227
+ `upstreamStub`: the runner calls each fixture-backed real handler with its
228
+ already-resolved fixture request, routes ProviderContext upstream transports to
229
+ the stub, and validates the result against the output schema. It never compares
230
+ the result to the recorded response because that evidence belongs to
231
+ `recordedAt`.
232
+
233
+ ```ts
234
+ import { runStandardTests } from "@apifuse/provider-sdk/testing";
235
+ import provider from "../index.js";
236
+
237
+ runStandardTests(provider, {
238
+ upstreamStub: ({ transport, method, url }) => {
239
+ if (
240
+ transport === "http" &&
241
+ method === "GET" &&
242
+ url === "https://api.example.test/flights"
243
+ ) {
244
+ return Response.json({ flights: [{ id: "fixture-flight" }] });
245
+ }
246
+ return undefined; // fails the test: live-network passthrough is forbidden
247
+ },
248
+ });
249
+ ```
250
+
251
+ The stub also identifies `stealth`, `browser`, and `native` interactions. Return
252
+ a Web `Response` or `{ status, headers, body }`; an unmatched call fails with
253
+ the operation, transport, and method named in the error. Browser handlers expose
254
+ method-level calls such as `goto`, `evaluate`, and `locator.click`, so provide a
255
+ canned result for each method the handler uses. Native connections similarly
256
+ identify `connectTcp`/`connectTls` and subsequent `write` calls. Direct global
257
+ `fetch` or socket usage is outside this ProviderContext seam and should not be
258
+ used by provider handlers.
108
259
 
109
260
  ### Health assertion context
110
261
 
@@ -130,15 +281,11 @@ healthCheck: {
130
281
  ```
131
282
  <!-- @magic-end:sample -->
132
283
 
133
- ### Strongly recommended (warn-level rules)
134
-
135
- - `description` includes "use" AND "when" phrasing
136
- - `inputExamples` with 2+ scenarios for complex input (nested objects, enums, format-sensitive strings)
137
- - `derivations` for parameters not directly visible in the user query (e.g., `gridX` derived from geocoding)
138
-
139
284
  ### Optional but valuable
140
285
 
141
- - `annotations`: `{ readOnly, destructive, idempotent, openWorld, rateLimit }` agentic safety signals
286
+ - `examples`: usage examples with locale-keyed `scenarioKey`, an `input`, and optional `rationaleKey`
287
+ - `approval`: only when it deliberately differs from the `riskClass` default (`read → never`, `write → risk-based`, otherwise `always`)
288
+ - `titleKey`, `summaryKey`, `markdownKey`, `whenToUseKeys`, `whenNotToUseKeys`, and `normalizationNotesKeys`: locale-keyed operation prose
142
289
  - `tags`: operation-level semantic tags for retrieval (e.g., `["weather", "korea", "realtime"]`)
143
290
  - `relatedOperations`: `{ alternatives?: string[] }` — links to fallback/sibling operations
144
291
 
@@ -152,10 +299,12 @@ level, then call `ctx.stt` from operation handlers or auth-flow handlers.
152
299
  ```ts
153
300
  export default defineProvider({
154
301
  id: "example-provider",
155
- // ...metadata, auth, operations, allowedHosts
302
+ // ...metadata, auth, allowedHosts
156
303
  stt: { mode: "required" },
304
+ })({
157
305
  operations: {
158
306
  verifyAudioOtp: {
307
+ riskClass: "read",
159
308
  input: z.object({
160
309
  audioBase64: z.string().describe("Base64-encoded short OTP audio"),
161
310
  mediaType: z.string().optional().describe("Audio MIME type"),
@@ -273,15 +422,17 @@ const paymentWebviewJourney = defineHealthJourney({
273
422
  ],
274
423
  });
275
424
 
276
- export default defineProvider({
425
+ const buildProvider = defineProvider({
277
426
  id: "example-provider",
278
- // ...metadata, auth, operations, allowedHosts
427
+ // ...metadata, auth, allowedHosts
279
428
  healthJourneys: [paymentWebviewJourney],
280
429
  });
430
+
431
+ export default buildProvider({ operations });
281
432
  ```
282
433
  <!-- @magic-end:sample -->
283
434
 
284
- The journey runner supplies `ctx.gateway`, `ctx.sms.waitForOtp()`, `ctx.journal.sideEffect()`, `ctx.state`, and `ctx.event.operation()` to the optional journey `run` function. Provider authors should keep `run` small: call the covered operations in step order, stop at the declared safe boundary, and let the generated health metadata carry schedule, timeout, required secret, and SMS matcher information to the health monitor.
435
+ The journey runner supplies `ctx.gateway`, `ctx.sms.waitForOtp()`, `ctx.journal.sideEffect()`, `ctx.state`, and `ctx.event.operation()` to the required journey `run` function. Provider authors should keep `run` small: call the covered operations in step order, stop at the declared safe boundary, and let the generated health metadata carry schedule, timeout, required secret, and SMS matcher information to the health monitor.
285
436
 
286
437
  For authenticated journeys, open a fresh connection inside `run` with `ctx.gateway.connect({ input: { ... } })`, execute covered operations with the returned `connectionId`, and disconnect in a `finally` block. Do not require or store long-lived `HEALTH_MONITOR_*_CONNECTION_ID` secrets; those stale connection IDs can hide broken login ceremonies.
287
438
 
@@ -309,6 +460,198 @@ External contributors are expected to submit standalone Provider source plus:
309
460
  Maintainers own monorepo import under `providers/<id>/`, registry generation,
310
461
  deployment projection checks, and release workflows.
311
462
 
463
+ ### Error responses
464
+
465
+ Provider-server failures use a stable public envelope:
466
+
467
+ ```json
468
+ {
469
+ "error": {
470
+ "code": "UPSTREAM_ERROR",
471
+ "message": "The upstream service failed",
472
+ "requestId": "req_123",
473
+ "retryable": true,
474
+ "details": { "providerReason": "temporarily_unavailable" }
475
+ }
476
+ }
477
+ ```
478
+
479
+ `retryable` is always present on responses emitted by the current SDK. Set
480
+ `retryable` in the `ProviderError` options when the provider knows the answer;
481
+ an explicit `true` or `false` wins over the matching operation declaration and
482
+ SDK derivation. When it is omitted, `operations.<id>.errorCodes[].retryable`
483
+ is used for a matching provider-owned code, followed by SDK derivation (which
484
+ defaults ordinary `ProviderError` values to `false`). During stateful rolling
485
+ upgrades, the forwarding client also accepts an older owner response that omits
486
+ `retryable` and treats it as `false` without loosening the emitted response
487
+ contract. Existing optional `fix` guidance is also preserved when a
488
+ `ProviderError` supplies it.
489
+
490
+ `details` belongs exclusively to the provider. The server passes
491
+ `ProviderError.options.details` through verbatim, including strings and arrays,
492
+ and never merges, overwrites, or wraps it. Do not put SDK taxonomy fields there.
493
+ SDK-owned validation and masked-internal-error paths retain their own diagnostic
494
+ details.
495
+
496
+ SDK observability is emitted separately in the
497
+ `X-ApiFuse-Error-Observability` response header as compact, single-line JSON:
498
+
499
+ ```json
500
+ {"category":"upstream_http","taxonomyVersion":"2026-05-26","retryable":true,"upstreamStatus":502}
501
+ ```
502
+
503
+ Treat this header as telemetry, not as provider-controlled public error detail.
504
+ Its category, taxonomy version, retryability, and optional upstream status match
505
+ the structured `provider_request_failed` log event.
506
+
507
+ Declare provider-owned operation failures directly on the operation. The
508
+ server builds a lookup once at startup and applies it to failures from that
509
+ operation:
510
+
511
+ ```ts
512
+ errorCodes: [{
513
+ code: "UPSTREAM_SCHEMA_ERROR",
514
+ status: 502,
515
+ retryable: true,
516
+ description: "The upstream response no longer matches its schema.",
517
+ }],
518
+ handler: async () => {
519
+ throw new ProviderError("Upstream schema changed", {
520
+ code: "UPSTREAM_SCHEMA_ERROR",
521
+ });
522
+ },
523
+ ```
524
+
525
+ `defineProvider` accepts only statuses the server can emit: 400, 401, 404, 429,
526
+ 500, 502, 503, and 504. Invalid declared statuses fail provider definition,
527
+ not a live request. Status selection uses this order:
528
+
529
+ 1. SDK-owned errors retain SDK status semantics. Operation declarations cannot
530
+ override SDK-owned codes, stateful-forwarding failures, Zod/deadline errors,
531
+ or `TransportError` values.
532
+ 2. A matching operation `errorCodes` entry with `status` supplies the status.
533
+ This slot applies to `ValidationError` as well as ordinary `ProviderError`.
534
+ 3. The registered mappings below apply.
535
+ 4. Existing fallbacks apply: `TransportError` 502/504, unregistered input
536
+ `ValidationError` 400 (output validation 500), and other unregistered
537
+ `ProviderError` values 500.
538
+
539
+ The registered mappings are:
540
+
541
+ | Error code or fallback | HTTP status |
542
+ | --- | ---: |
543
+ | `AUTH_REQUIRED`, `reauth_required` | 401 |
544
+ | `MISSING_SECRET` | 400 |
545
+ | `NOT_FOUND`, `not_found`, `NO_DATA` | 404 |
546
+ | `RATE_LIMITED`, `UPSTREAM_RATE_LIMIT`, `LIMITED_NUMBER_OF_SERVICE_REQUESTS_EXCEEDS_ERROR` | 429 |
547
+ | `UPSTREAM_ERROR`, `BLOCKED` | 502 |
548
+ | `STT_UNAVAILABLE`, `UNSUPPORTED_STT_BACKEND`, `STATEFUL_FORWARDING_REPLAY_CACHE_FULL` | 503 |
549
+ | Unregistered input `ValidationError` code | 400 |
550
+ | Other unregistered `ProviderError` code | 500 |
551
+
552
+ An unregistered non-validation `ProviderError` code returns HTTP 500 and emits
553
+ the greppable `unregistered_provider_error_code` signal with the code in the
554
+ structured failure log. A matching operation declaration, including one that
555
+ omits `status`, makes the code registered for this signal and may independently
556
+ supply `retryable`. The HTTP 400 `ValidationError` behavior is only the fallback
557
+ when neither an operation status nor a registered mapping applies.
558
+
559
+ Throw the domain `ProviderError` directly. Subclassing or wrapping it as a
560
+ `TransportError` solely to preserve a 5xx response is obsolete; declare the
561
+ domain code's `status` instead. Genuine `TransportError` values remain
562
+ SDK-owned and keep their 502/504 mapping.
563
+
564
+ ### Declared secrets are SDK-enforced
565
+
566
+ Environment/secret presence validation is single-sourced in the SDK. Declare
567
+ every env secret the provider needs in `defineProvider`:
568
+
569
+ ```ts
570
+ secrets: [
571
+ {
572
+ name: "APIFUSE__PROVIDER__MY_PROVIDER__API_KEY",
573
+ required: true,
574
+ description: "Upstream API key from the vendor portal",
575
+ },
576
+ ],
577
+ ```
578
+
579
+ The runtime validates every `required: true` declaration before any operation
580
+ handler or auth-flow handler (except `abort`) runs. When a required secret is
581
+ unset or whitespace-only, the invocation fails with the canonical structured
582
+ error — code `MISSING_SECRET`, HTTP 400, top-level `retryable: false`, and a
583
+ `fix` naming every missing secret — across `/v1/{operation}`, self-test probes,
584
+ `apifuse perf`, and `apifuse record`. Its error-observability header carries the
585
+ `credential_unavailable` category. The server also emits a
586
+ `provider_secrets_missing` warn log at boot so unprovisioned deployments are
587
+ visible immediately without crashing the pod.
588
+
589
+ Provider-local presence re-validation is **deprecated**: do not write
590
+ `requireServiceKey`/`requireApiKey`-style guards that re-check `ctx.env.get()`
591
+ and throw a hand-rolled `CONFIGURATION_ERROR`/`MISSING_SECRET`. Those guards
592
+ are dead weight (the SDK gate runs first) and historically diverged into
593
+ inconsistent error shapes. The `sdk-owned-secret-presence` submit-check rule
594
+ flags them at warn level; acknowledge a deliberate exception with
595
+ `// @apifuse-allow sdk-owned-secret-presence: <reason>`.
596
+
597
+ ```ts
598
+ // Before (deprecated): provider-local double validation
599
+ function requireServiceKey(ctx: ProviderContext): string {
600
+ const value = ctx.env.get(SERVICE_KEY_ENV);
601
+ if (!value?.trim()) {
602
+ throw new ProviderError(`Missing required provider secret: ${SERVICE_KEY_ENV}`, {
603
+ code: "CONFIGURATION_ERROR",
604
+ });
605
+ }
606
+ return value;
607
+ }
608
+
609
+ // After: declare { name: SERVICE_KEY_ENV, required: true } and read directly.
610
+ const serviceKey = ctx.env.get(SERVICE_KEY_ENV);
611
+ ```
612
+
613
+ Note the asymmetry: the gate treats whitespace-only values as missing, but
614
+ `ctx.env.get()` still returns the raw value to handlers — trim at the point of
615
+ use if the upstream is whitespace-sensitive.
616
+
617
+ ### Credentials forced into query parameters
618
+
619
+ Prefer an authorization header or request body whenever the upstream supports
620
+ one. When the upstream requires a credential in the URL query (for example
621
+ `serviceKey`, `confmKey`, or `crtfc_key`), use `sensitiveParams`:
622
+
623
+ ```ts
624
+ const response = await ctx.http.get("/openapi/lookup", {
625
+ params: { pageNo: 1, numOfRows: 100 },
626
+ sensitiveParams: {
627
+ serviceKey: ctx.env.get("APIFUSE__PROVIDER__EXAMPLE__SERVICE_KEY")!,
628
+ },
629
+ });
630
+ ```
631
+
632
+ `sensitiveParams` is merged into the outgoing query like `params`, while its
633
+ values are redacted from SDK transport errors, traces, and `apifuse record`
634
+ fixtures. Do not put query credentials in `params`, and do not hand-build a URL
635
+ containing a key; those paths cannot declare which query values are secret.
636
+
637
+ #### Residual risks
638
+
639
+ Redaction is unconditional in structural positions (declared query keys and
640
+ exact scalar fixture/error fields) for values of every length. In unstructured
641
+ free text, values of four or more characters are replaced as substrings; shorter
642
+ values are replaced only at token boundaries to avoid corrupting unrelated text
643
+ (for example, a secret `api` must not rewrite `rapid`). The residual risk is that
644
+ a sub-four-character secret embedded directly inside a larger alphanumeric token
645
+ can remain in free text. Prefer a higher-entropy credential, or a header/body
646
+ credential channel, whenever the upstream permits it. An empty
647
+ `sensitiveParams: {}` is treated exactly as if the option were omitted.
648
+
649
+ For `session.redirects.run()`, returned hop URLs are diagnostic metadata and
650
+ therefore keep declared query values and common response-only credential keys
651
+ redacted. If a login flow must consume a rotated credential from `Location`,
652
+ inspect it inside `stopWhen`; that callback receives the real hop while callback
653
+ failures are sanitized before propagation.
654
+
312
655
  ### Public local debugging checklist
313
656
 
314
657
  - Operation smoke requests use the provider server envelope:
@@ -326,7 +669,7 @@ deployment projection checks, and release workflows.
326
669
  HTML, or upstream `Error` objects.
327
670
 
328
671
  ```ts
329
- export default defineProvider({
672
+ const buildProvider = defineProvider({
330
673
  id: "example-provider",
331
674
  version: "1.0.0",
332
675
  runtime: "standard",
@@ -360,8 +703,10 @@ export default defineProvider({
360
703
  },
361
704
  },
362
705
  credential: { keys: ["cookie"] },
363
- // ...metadata and operations
706
+ // ...metadata
364
707
  });
708
+
709
+ export default buildProvider({ operations });
365
710
  ```
366
711
 
367
712
  - Credentials auth providers should use `defineCredentialsAuth()` instead of
@@ -388,15 +733,17 @@ const credentialsAuth = defineCredentialsAuth({
388
733
  },
389
734
  });
390
735
 
391
- export default defineProvider({
736
+ const buildProvider = defineProvider({
392
737
  id: "example-provider",
393
738
  version: "1.0.0",
394
739
  runtime: "standard",
395
740
  auth: credentialsAuth.auth,
396
741
  credential: credentialsAuth.credential,
397
742
  context: credentialsAuth.context,
398
- // ...metadata and operations
743
+ // ...metadata
399
744
  });
745
+
746
+ export default buildProvider({ operations });
400
747
  ```
401
748
 
402
749
  For OTP, MFA, CAPTCHA handoff, or user-approved login, return a challenge from
@@ -456,14 +803,171 @@ const credentialsAuth = defineCredentialsAuth({
456
803
  request's `context`.
457
804
  - Stealth/browser providers may require local runtime setup outside Provider code:
458
805
  keep access-sensitive operations on `ctx.stealth.fetch()` with an SDK stealth
459
- `profile`; the TypeScript runtime uses `impit` behind that interface, so do
806
+ `profile`; the TypeScript runtime uses `wreq-js` behind that interface, so do
460
807
  not add per-operation JA3, HTTP/2 SETTINGS, or pseudo-header tuning. `ctx.stealth`
461
- supports Chrome/Firefox-style profiles; use `browser.engine:
462
- "playwright-stealth"` for Safari-specific or real browser Providers
463
- (`nodriver` is Python-runtime only); install local browser assets with
808
+ supports Chrome, Firefox, and Safari profiles; use `ctx.browser` when a
809
+ Provider needs real browser execution. TypeScript browser Providers use
810
+ `browser.engine: "playwright-stealth"` (`nodriver` is Python-runtime only);
811
+ install local browser assets with
464
812
  `bunx playwright install chromium`, or set
465
813
  `APIFUSE__CDP_POOL__URL` for remote browser debugging.
466
814
 
815
+ ### Native gateway adapter migration
816
+
817
+ Native proxy resolution supports both HTTP CONNECT and SOCKS5 without
818
+ terminating origin TLS. The built-in vendor order follows `proxy.providers`
819
+ exactly: `smartproxy` means the `api.smartproxy.org` allocation vendor (raw
820
+ `ip:port` endpoints), while `nodemaven` is the credentialed gateway. It is not
821
+ the company formerly called Smartproxy; that separate company is represented
822
+ by the deprecated `decodo` name.
823
+
824
+ Custom `gatewaySynthesizers` must now accept the selected `protocol` and the
825
+ injected `credentials` resolver on `NativeGatewayProxySynthesisInput`.
826
+ Synthesizers may be async because allocation vendors perform network I/O. They
827
+ may return a proxy, `undefined` when they do not implement the offered vendor,
828
+ or `{ kind: "skipped", reason }` so an exhausted required chain can explain an
829
+ absent credential, unsupported protocol, or allocation failure. Accordingly,
830
+ `resolveNativeGatewayProxy(...)` must now be awaited.
831
+
832
+ Callers that do not supply custom synthesizers or credentials keep env-backed
833
+ behavior. Hosts that already have an allowlisted `EnvContext` can inject it
834
+ explicitly, and vault-backed or per-tenant hosts can supply their own resolver:
835
+
836
+ ```ts
837
+ import {
838
+ createEnvVendorCredentialResolver,
839
+ createNativeNetworkClient,
840
+ } from "@apifuse/provider-sdk";
841
+
842
+ const network = createNativeNetworkClient({
843
+ proxyPolicy: { mode: "required", providers: ["smartproxy", "nodemaven"] },
844
+ credentials: createEnvVendorCredentialResolver(ctx.env),
845
+ // Optional advanced override; omit for each vendor's default.
846
+ proxyProtocol: "socks5",
847
+ });
848
+ ```
849
+
850
+ Never include credential values in adapter skip messages or thrown errors. The
851
+ SDK redacts built-in proxy URL userinfo, CONNECT authentication, and allocator
852
+ causes, but a custom adapter remains responsible for not publishing secrets in
853
+ its own diagnostics.
854
+
855
+ ### Limiting stealth response bodies
856
+
857
+ Set `maxBodyBytes` on `ctx.stealth.fetch()` or `session.redirects.run()` when an
858
+ upstream response has a known safe maximum. The limit is opt-in and counts
859
+ decoded bytes as `wreq-js` streams them. It applies to every redirect hop, uses a
860
+ parseable `Content-Length` for an early rejection, and still enforces the limit
861
+ incrementally when the header is absent or inaccurate. Exceeding the limit
862
+ aborts the response and throws a non-retryable `TransportError` with code
863
+ `response_too_large`.
864
+
865
+ Pass the limit to the transport instead of checking `Content-Length` in provider
866
+ code:
867
+
868
+ ```ts
869
+ const response = await ctx.stealth.fetch("/api/search", {
870
+ params: { query: input.query },
871
+ maxBodyBytes: 2 * 1024 * 1024,
872
+ })
873
+ ```
874
+
875
+ ### Persisting stealth session cookies
876
+
877
+ Persist `session.cookies.serialize()` as JSON when an authenticated session must
878
+ survive a restart or move to another replica. The returned
879
+ `StealthCookieStoreV1` has an explicit version and retains every cookie together
880
+ with its Domain, Path, Secure, expiry, host-only, and other cookie attributes.
881
+ Restore it with `session.cookies.deserialize()`. Unsupported future versions
882
+ fail explicitly instead of being accepted as a partial cookie jar.
883
+
884
+ Credential values are strings, so stringify the store at the credential
885
+ boundary and parse it when rebuilding the session:
886
+
887
+ ```ts
888
+ // After login (including any redirects across sibling hosts):
889
+ const result = await session.redirects.run({ url: loginUrl });
890
+ return {
891
+ credential: {
892
+ cookieStore: JSON.stringify(result.cookieStore),
893
+ },
894
+ };
895
+
896
+ // In a later operation or replica:
897
+ const persisted = ctx.credential.get("cookieStore");
898
+ if (persisted) {
899
+ session.cookies.deserialize(JSON.parse(persisted));
900
+ }
901
+ ```
902
+
903
+ `snapshot()` and `restore()` remain only for backward compatibility with flat
904
+ `Record<string, string>` credentials. `snapshot()` enumerates cookies across all
905
+ hosts and paths, but the flat shape is inherently lossy: duplicate names
906
+ collapse and Domain, Path, Secure, expiry, and host-only attributes cannot be
907
+ represented. `restore()` therefore recreates host-only `Path=/` cookies on the
908
+ session base origin. Do not use the flat form for new persistence code. Cookie
909
+ headers remain origin-filtered: use `toHeader(url)` for a particular request and
910
+ never build a request header from serialized or snapshotted persistence data.
911
+
912
+ ### Recording and replaying streaming responses
913
+
914
+ `apifuse record` passes responses returned by `ctx.http.stream()` directly to the operation
915
+ handler while incrementally capturing a bounded preview. If the handler returns or cancels its
916
+ reader before EOF, the recorder drains the retained upstream reader before writing a JSON evidence
917
+ record to `__fixtures__/raw.json`. The record contains the status, success
918
+ flag, `content-type`/`content-length`/`content-disposition` headers when present, the
919
+ full body SHA-256 and byte count, and a base64 preview up to the configured stream preview limit.
920
+ Textual previews are decoded and passed through the fixture sanitizer before base64 encoding.
921
+ Classification uses both the declared content type and the preview bytes, so missing or incorrect
922
+ content-type headers do not bypass sanitization. PEM private-key blocks and long high-entropy
923
+ tokens in otherwise unstructured text are redacted as well. If the full preview is not valid UTF-8,
924
+ the entire lossy-decoded preview is scanned and matching decodable byte windows are sanitized. Only a
925
+ magic-number-confirmed binary preview with no textual-secret pattern anywhere in the preview bypasses
926
+ sanitization; other undecodable data fails closed.
927
+ Sanitized previews carry `preview_sanitized: true`, plus a
928
+ `preview_redaction_reason` when capture had to fail closed. The original hash and byte count always
929
+ describe upstream bytes, not a sanitized preview.
930
+
931
+ Each record includes query-free request provenance (`method`, `path`, and a one-based stream call
932
+ ordinal). Provenance never stores the origin, URL userinfo, query, or fragment. Every retained path
933
+ segment is scrubbed before persistence: credential-key segments, values following those keys,
934
+ known token shapes, and long high-entropy opaque segments become `[REDACTED]`. If an operation
935
+ opens multiple streams, the recorder finalizes every retained reader and
936
+ writes all evidence records in stream call order. Stream invocations use a tagged capture envelope
937
+ whose items distinguish stream evidence from ordinary JSON responses. Evidence-only snapshot replay
938
+ consumes that exact call order and fails immediately when evidence is exhausted or a call kind is
939
+ reordered. When request provenance is present, replay also rejects method or path changes (relative
940
+ URLs are resolved against the recorded path prefix); ordinals remain diagnostic and are not matched.
941
+ Appended fixtures replay a stream envelope only when it is the latest invocation. SSE
942
+ recording remains unsupported and fails explicitly instead of retaining an unrelated earlier
943
+ response.
944
+
945
+ #### Residual risks
946
+
947
+ - Credential-path sanitization decodes each URL path segment once. Double-encoded separators or
948
+ values such as `%252F` are not decoded recursively, so they can conceal a credential-shaped
949
+ segment from the recorder. This single-pass policy keeps path handling deterministic and avoids
950
+ interpreting ambiguous or intentionally layered encodings differently from the upstream. Never
951
+ place credentials in URL paths, and review recorded provenance before committing fixtures.
952
+ - Primitive strings embedded in prose are redacted only when they match the current PEM,
953
+ credential-assignment, known-token, or entropy heuristics. Other secret formats can remain because
954
+ blanket redaction of ordinary strings would destroy useful fixture content and create broad false
955
+ positives. Keep secrets under credential-named structured fields where possible and manually
956
+ inspect sanitized fixture text before committing it.
957
+
958
+ Stream fixture replay in `runStandardTests(..., { snapshot: true })` is evidence-only:
959
+ `ctx.http.stream()` returns a usable stream containing exactly the recorded preview,
960
+ not a fabricated full body. The replay response also carries runtime metadata
961
+ `evidence_only: true`, `body_sha256`, `body_bytes`, and the optional preview sanitization fields
962
+ for assertions about the original capture. Do not assert that the replay body hashes to
963
+ `body_sha256` when `body_bytes`
964
+ exceeds the decoded preview length or `preview_sanitized` is present; use the metadata for
965
+ full-body integrity and limit body-content assertions to the preview.
966
+
967
+ Golden snapshot suites can set `requireSnapshot: true` so a missing committed snapshot fails instead
968
+ of being created implicitly. Regenerate intentional changes with
969
+ `bun test --update-snapshots`; review and commit the resulting `transform.snap.json` file.
970
+
467
971
  ### Running the pre-submission report
468
972
 
469
973
  ```bash