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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (478) hide show
  1. package/AUTHORING.md +943 -51
  2. package/CHANGELOG.md +273 -1
  3. package/LICENSE +21 -0
  4. package/README.md +117 -29
  5. package/SUBMISSION.md +3 -2
  6. package/bin/apifuse-check.ts +293 -13
  7. package/bin/apifuse-dev.ts +42 -19
  8. package/bin/apifuse-migrate-deployment.ts +200 -0
  9. package/bin/apifuse-migrate-operation-declaration.ts +55 -0
  10. package/bin/apifuse-migrate-shape.ts +202 -0
  11. package/bin/apifuse-pack-check.ts +19 -6
  12. package/bin/apifuse-pack-smoke.ts +57 -2
  13. package/bin/apifuse-pack-types.ts +736 -38
  14. package/bin/apifuse-perf.ts +59 -23
  15. package/bin/apifuse-record.ts +923 -94
  16. package/bin/apifuse-submit-check.ts +2313 -281
  17. package/bin/apifuse-test.ts +3 -1
  18. package/bin/submit-check-delimited-text.ts +50 -0
  19. package/dist/auth-turn/index.d.ts +3 -3
  20. package/dist/auth-turn/index.js +1 -1
  21. package/dist/auth.d.ts +14 -0
  22. package/dist/auth.js +67 -0
  23. package/dist/ceremonies/index.d.ts +16 -0
  24. package/dist/ceremonies/index.js +141 -36
  25. package/dist/cli/commands.d.ts +1 -1
  26. package/dist/cli/commands.js +30 -0
  27. package/dist/cli/create.d.ts +1 -1
  28. package/dist/cli/create.js +8 -2
  29. package/dist/cli/deployment-intent.d.ts +178 -0
  30. package/dist/cli/deployment-intent.js +277 -0
  31. package/dist/cli/local-connection.d.ts +111 -0
  32. package/dist/cli/local-connection.js +151 -0
  33. package/dist/cli/migrate-deployment-intent.d.ts +132 -0
  34. package/dist/cli/migrate-deployment-intent.js +1552 -0
  35. package/dist/cli/migrate-operation-declaration.d.ts +70 -0
  36. package/dist/cli/migrate-operation-declaration.js +2206 -0
  37. package/dist/cli/migrate-operation-shape.d.ts +44 -0
  38. package/dist/cli/migrate-operation-shape.js +113 -0
  39. package/dist/cli/migrate-provider-shape.d.ts +56 -0
  40. package/dist/cli/migrate-provider-shape.js +580 -0
  41. package/dist/cli/resolver-runtime.d.ts +21 -0
  42. package/dist/cli/resolver-runtime.js +31 -0
  43. package/dist/cli/templates/provider/.agents/skills/health-checks-and-fail-closed/SKILL.md.tpl +141 -23
  44. package/dist/cli/templates/provider/Dockerfile.tpl +1 -1
  45. package/dist/cli/templates/provider/README.md.tpl +41 -19
  46. package/dist/cli/templates/provider/index.ts.tpl +6 -3
  47. package/dist/cli/templates/provider/operations/ping.ts.tpl +4 -1
  48. package/dist/cli/templates/provider/provider.json.tpl +6 -0
  49. package/dist/config/loader.d.ts +202 -16
  50. package/dist/config/loader.js +491 -141
  51. package/dist/contract-serialization.js +4 -8
  52. package/dist/contract-types.d.ts +12 -5
  53. package/dist/contract.js +24 -10
  54. package/dist/declaration-validation.d.ts +34 -0
  55. package/dist/declaration-validation.js +305 -0
  56. package/dist/define.d.ts +71 -29
  57. package/dist/define.js +807 -69
  58. package/dist/dev.d.ts +5 -0
  59. package/dist/dev.js +8 -1
  60. package/dist/engine.d.ts +129 -0
  61. package/dist/engine.js +209 -0
  62. package/dist/error-observability.d.ts +7 -0
  63. package/dist/error-observability.js +61 -0
  64. package/dist/error-resolution.d.ts +18 -0
  65. package/dist/error-resolution.js +243 -0
  66. package/dist/errors.d.ts +74 -0
  67. package/dist/errors.js +99 -0
  68. package/dist/fixture-sanitization.d.ts +28 -0
  69. package/dist/fixture-sanitization.js +371 -0
  70. package/dist/handle-meta.d.ts +90 -0
  71. package/dist/handle-meta.js +73 -0
  72. package/dist/handle.d.ts +226 -0
  73. package/dist/handle.js +345 -0
  74. package/dist/health-scenario.d.ts +1901 -0
  75. package/dist/health-scenario.js +653 -0
  76. package/dist/i18n/catalog.js +21 -1
  77. package/dist/i18n/error-messages.d.ts +86 -0
  78. package/dist/i18n/error-messages.js +192 -0
  79. package/dist/i18n/index.d.ts +1 -0
  80. package/dist/i18n/index.js +1 -0
  81. package/dist/i18n/keys.d.ts +12 -0
  82. package/dist/i18n/keys.js +76 -5
  83. package/dist/i18n/operation-locale-namespace.d.ts +2 -0
  84. package/dist/i18n/operation-locale-namespace.js +7 -0
  85. package/dist/index.d.ts +40 -15
  86. package/dist/index.js +29 -11
  87. package/dist/lint.d.ts +43 -11
  88. package/dist/lint.js +2512 -177
  89. package/dist/native-address.d.ts +43 -0
  90. package/dist/native-address.js +281 -0
  91. package/dist/native-egress-policy.d.ts +31 -0
  92. package/dist/native-egress-policy.js +288 -0
  93. package/dist/observability.d.ts +5 -2
  94. package/dist/observability.js +48 -1
  95. package/dist/provider.d.ts +18 -8
  96. package/dist/provider.js +11 -6
  97. package/dist/runtime/auth-flow.d.ts +6 -1
  98. package/dist/runtime/auth-flow.js +8 -0
  99. package/dist/runtime/bounded-expiring-map.d.ts +21 -0
  100. package/dist/runtime/bounded-expiring-map.js +64 -0
  101. package/dist/runtime/browser-telemetry-binding.d.ts +5 -0
  102. package/dist/runtime/browser-telemetry-binding.js +83 -0
  103. package/dist/runtime/browser-telemetry.d.ts +76 -0
  104. package/dist/runtime/browser-telemetry.js +165 -0
  105. package/dist/runtime/browser.d.ts +4 -0
  106. package/dist/runtime/browser.js +688 -83
  107. package/dist/runtime/cache-telemetry.d.ts +71 -0
  108. package/dist/runtime/cache-telemetry.js +177 -0
  109. package/dist/runtime/cache.d.ts +3 -0
  110. package/dist/runtime/cache.js +245 -23
  111. package/dist/runtime/capability-response.d.ts +3 -0
  112. package/dist/runtime/capability-response.js +56 -0
  113. package/dist/runtime/capability-telemetry.d.ts +46 -0
  114. package/dist/runtime/capability-telemetry.js +68 -0
  115. package/dist/runtime/chrome149-header-order.d.ts +58 -0
  116. package/dist/runtime/chrome149-header-order.js +289 -0
  117. package/dist/runtime/diagnostic-env-values.d.ts +5 -0
  118. package/dist/runtime/diagnostic-env-values.js +57 -0
  119. package/dist/runtime/diagnostic-env.d.ts +14 -0
  120. package/dist/runtime/diagnostic-env.js +44 -0
  121. package/dist/runtime/diagnostic-redactor.d.ts +54 -0
  122. package/dist/runtime/diagnostic-redactor.js +571 -0
  123. package/dist/runtime/egress-lease.d.ts +65 -0
  124. package/dist/runtime/egress-lease.js +236 -0
  125. package/dist/runtime/engine-mode.d.ts +74 -0
  126. package/dist/runtime/engine-mode.js +152 -0
  127. package/dist/runtime/env.js +14 -1
  128. package/dist/runtime/executor.d.ts +3 -2
  129. package/dist/runtime/executor.js +23 -26
  130. package/dist/runtime/handle-wordlist.d.ts +43 -0
  131. package/dist/runtime/handle-wordlist.js +256 -0
  132. package/dist/runtime/handle.d.ts +71 -0
  133. package/dist/runtime/handle.js +908 -0
  134. package/dist/runtime/http-telemetry-binding.d.ts +10 -0
  135. package/dist/runtime/http-telemetry-binding.js +152 -0
  136. package/dist/runtime/http-telemetry-guard.d.ts +16 -0
  137. package/dist/runtime/http-telemetry-guard.js +202 -0
  138. package/dist/runtime/http-telemetry.d.ts +104 -0
  139. package/dist/runtime/http-telemetry.js +190 -0
  140. package/dist/runtime/http.d.ts +34 -0
  141. package/dist/runtime/http.js +680 -121
  142. package/dist/runtime/insights.js +2 -2
  143. package/dist/runtime/instrumentation.d.ts +2 -2
  144. package/dist/runtime/instrumentation.js +462 -19
  145. package/dist/runtime/native-network-errors.d.ts +33 -0
  146. package/dist/runtime/native-network-errors.js +69 -0
  147. package/dist/runtime/native-network.d.ts +105 -0
  148. package/dist/runtime/native-network.js +1433 -0
  149. package/dist/runtime/native-telemetry.d.ts +142 -0
  150. package/dist/runtime/native-telemetry.js +231 -0
  151. package/dist/runtime/ocr-telemetry.d.ts +82 -0
  152. package/dist/runtime/ocr-telemetry.js +192 -0
  153. package/dist/runtime/ocr.d.ts +29 -0
  154. package/dist/runtime/ocr.js +468 -0
  155. package/dist/runtime/otlp.d.ts +71 -2
  156. package/dist/runtime/otlp.js +398 -16
  157. package/dist/runtime/provider.d.ts +7 -0
  158. package/dist/runtime/provider.js +14 -0
  159. package/dist/runtime/proxy-errors.js +6 -2
  160. package/dist/runtime/proxy-nodemaven.d.ts +56 -0
  161. package/dist/runtime/proxy-nodemaven.js +147 -0
  162. package/dist/runtime/proxy-retry-policy.d.ts +4 -1
  163. package/dist/runtime/proxy-retry-policy.js +11 -2
  164. package/dist/runtime/proxy-telemetry.d.ts +133 -3
  165. package/dist/runtime/proxy-telemetry.js +218 -70
  166. package/dist/runtime/redirect-hop-headers.d.ts +19 -0
  167. package/dist/runtime/redirect-hop-headers.js +58 -0
  168. package/dist/runtime/redirects.d.ts +61 -0
  169. package/dist/runtime/redirects.js +149 -0
  170. package/dist/runtime/redis.d.ts +1 -1
  171. package/dist/runtime/redis.js +4 -2
  172. package/dist/runtime/request-options.d.ts +75 -1
  173. package/dist/runtime/request-options.js +588 -0
  174. package/dist/runtime/request-telemetry.d.ts +70 -0
  175. package/dist/runtime/request-telemetry.js +229 -0
  176. package/dist/runtime/resolver-config.d.ts +13 -0
  177. package/dist/runtime/resolver-config.js +14 -0
  178. package/dist/runtime/resolver-public.d.ts +3 -0
  179. package/dist/runtime/resolver-public.js +1 -0
  180. package/dist/runtime/resolver-runtime-options.d.ts +14 -0
  181. package/dist/runtime/resolver-runtime-options.js +33 -0
  182. package/dist/runtime/resolver-shared.d.ts +24 -0
  183. package/dist/runtime/resolver-shared.js +69 -0
  184. package/dist/runtime/resolver-span-attributes.d.ts +34 -0
  185. package/dist/runtime/resolver-span-attributes.js +93 -0
  186. package/dist/runtime/resolver-telemetry.d.ts +135 -0
  187. package/dist/runtime/resolver-telemetry.js +204 -0
  188. package/dist/runtime/resolver-usage.d.ts +32 -0
  189. package/dist/runtime/resolver-usage.js +54 -0
  190. package/dist/runtime/resolver-vendors/bindings.d.ts +53 -0
  191. package/dist/runtime/resolver-vendors/bindings.js +45 -0
  192. package/dist/runtime/resolver-vendors/browser.d.ts +24 -0
  193. package/dist/runtime/resolver-vendors/browser.js +423 -0
  194. package/dist/runtime/resolver-vendors/capsolver.d.ts +22 -0
  195. package/dist/runtime/resolver-vendors/capsolver.js +544 -0
  196. package/dist/runtime/resolver-vendors/hosts.d.ts +23 -0
  197. package/dist/runtime/resolver-vendors/hosts.js +68 -0
  198. package/dist/runtime/resolver-vendors/hypersolutions.d.ts +27 -0
  199. package/dist/runtime/resolver-vendors/hypersolutions.js +369 -0
  200. package/dist/runtime/resolver-vendors/twocaptcha.d.ts +24 -0
  201. package/dist/runtime/resolver-vendors/twocaptcha.js +425 -0
  202. package/dist/runtime/resolver-vendors/types.d.ts +125 -0
  203. package/dist/runtime/resolver-vendors/types.js +106 -0
  204. package/dist/runtime/resolver.d.ts +79 -0
  205. package/dist/runtime/resolver.js +1094 -0
  206. package/dist/runtime/state-telemetry.d.ts +79 -0
  207. package/dist/runtime/state-telemetry.js +194 -0
  208. package/dist/runtime/state.d.ts +10 -1
  209. package/dist/runtime/state.js +322 -82
  210. package/dist/runtime/stealth-akamai-sbsd.d.ts +54 -0
  211. package/dist/runtime/stealth-akamai-sbsd.js +142 -0
  212. package/dist/runtime/stealth-cookies.d.ts +24 -0
  213. package/dist/runtime/stealth-cookies.js +131 -0
  214. package/dist/runtime/stealth-owned-headers.d.ts +39 -0
  215. package/dist/runtime/stealth-owned-headers.js +57 -0
  216. package/dist/runtime/stealth-telemetry.d.ts +92 -0
  217. package/dist/runtime/stealth-telemetry.js +179 -0
  218. package/dist/runtime/stealth.d.ts +45 -6
  219. package/dist/runtime/stealth.js +1775 -320
  220. package/dist/runtime/stt-telemetry.d.ts +77 -0
  221. package/dist/runtime/stt-telemetry.js +176 -0
  222. package/dist/runtime/stt.js +18 -19
  223. package/dist/runtime/timeout.d.ts +5 -0
  224. package/dist/runtime/timeout.js +12 -0
  225. package/dist/runtime/trace-config.d.ts +12 -0
  226. package/dist/runtime/trace-config.js +62 -0
  227. package/dist/runtime/trace.d.ts +17 -0
  228. package/dist/runtime/trace.js +176 -25
  229. package/dist/runtime-boundary-lint.d.ts +137 -0
  230. package/dist/runtime-boundary-lint.js +590 -0
  231. package/dist/schema.d.ts +20 -0
  232. package/dist/schema.js +72 -2
  233. package/dist/serve.d.ts +1 -1
  234. package/dist/serve.js +1 -1
  235. package/dist/server/error-observability.d.ts +1 -0
  236. package/dist/server/error-observability.js +1 -0
  237. package/dist/server/error-stack-frames.d.ts +35 -0
  238. package/dist/server/error-stack-frames.js +219 -0
  239. package/dist/server/index.d.ts +21 -2
  240. package/dist/server/index.js +11 -2
  241. package/dist/server/runtime-diagnostics.d.ts +165 -0
  242. package/dist/server/runtime-diagnostics.js +360 -0
  243. package/dist/server/sdk-version.d.ts +3 -0
  244. package/dist/server/sdk-version.js +19 -0
  245. package/dist/server/self-test-input-tokens.d.ts +2 -1
  246. package/dist/server/self-test-input-tokens.js +18 -14
  247. package/dist/server/self-test-redaction.js +8 -33
  248. package/dist/server/self-test.d.ts +18 -3
  249. package/dist/server/self-test.js +139 -76
  250. package/dist/server/sensitive-values.d.ts +26 -0
  251. package/dist/server/sensitive-values.js +137 -0
  252. package/dist/server/serve-implementation.d.ts +285 -0
  253. package/dist/server/serve-implementation.js +3172 -0
  254. package/dist/server/serve.d.ts +1 -75
  255. package/dist/server/serve.js +1 -1170
  256. package/dist/server/state-backend-report.d.ts +70 -0
  257. package/dist/server/state-backend-report.js +113 -0
  258. package/dist/server/trace-output.d.ts +7 -0
  259. package/dist/server/trace-output.js +111 -0
  260. package/dist/server/types.d.ts +37 -5
  261. package/dist/server/types.js +34 -1
  262. package/dist/stateful/errors.d.ts +19 -0
  263. package/dist/stateful/errors.js +24 -0
  264. package/dist/stateful/http-provider-event-emitter.d.ts +40 -0
  265. package/dist/stateful/http-provider-event-emitter.js +237 -0
  266. package/dist/stateful/http-session-owner-registry.d.ts +44 -0
  267. package/dist/stateful/http-session-owner-registry.js +210 -0
  268. package/dist/stateful/index.d.ts +18 -0
  269. package/dist/stateful/index.js +18 -0
  270. package/dist/stateful/provider-event-delivery-failures.d.ts +32 -0
  271. package/dist/stateful/provider-event-delivery-failures.js +43 -0
  272. package/dist/stateful/provider-event-pipeline-metrics.d.ts +46 -0
  273. package/dist/stateful/provider-event-pipeline-metrics.js +48 -0
  274. package/dist/stateful/provider-event-pipeline.d.ts +50 -0
  275. package/dist/stateful/provider-event-pipeline.js +1 -0
  276. package/dist/stateful/provider-events.d.ts +101 -0
  277. package/dist/stateful/provider-events.js +289 -0
  278. package/dist/stateful/session-key.d.ts +15 -0
  279. package/dist/stateful/session-key.js +86 -0
  280. package/dist/stateful/stateful-provider-adapter-context.d.ts +5 -0
  281. package/dist/stateful/stateful-provider-adapter-context.js +42 -0
  282. package/dist/stateful/stateful-provider-adapter-metrics.d.ts +15 -0
  283. package/dist/stateful/stateful-provider-adapter-metrics.js +21 -0
  284. package/dist/stateful/stateful-provider-adapter.d.ts +98 -0
  285. package/dist/stateful/stateful-provider-adapter.js +287 -0
  286. package/dist/stateful/stateful-provider-observability.d.ts +62 -0
  287. package/dist/stateful/stateful-provider-observability.js +161 -0
  288. package/dist/stateful/stateful-provider-owner-forwarder.d.ts +41 -0
  289. package/dist/stateful/stateful-provider-owner-forwarder.js +237 -0
  290. package/dist/stateful/stateful-provider-runtime-context.d.ts +35 -0
  291. package/dist/stateful/stateful-provider-runtime-context.js +61 -0
  292. package/dist/stateful/stateful-provider-runtime-executor.d.ts +34 -0
  293. package/dist/stateful/stateful-provider-runtime-executor.js +52 -0
  294. package/dist/stateful/stateful-provider-session-routing.d.ts +67 -0
  295. package/dist/stateful/stateful-provider-session-routing.js +345 -0
  296. package/dist/stateful/stateful-provider-session-runtime.d.ts +98 -0
  297. package/dist/stateful/stateful-provider-session-runtime.js +245 -0
  298. package/dist/stateful-signing.d.ts +18 -0
  299. package/dist/stateful-signing.js +27 -0
  300. package/dist/stealth/profiles.d.ts +15 -4
  301. package/dist/stealth/profiles.js +169 -211
  302. package/dist/stream-evidence.d.ts +74 -0
  303. package/dist/stream-evidence.js +785 -0
  304. package/dist/stream.js +7 -1
  305. package/dist/testing/index.d.ts +2 -1
  306. package/dist/testing/index.js +2 -1
  307. package/dist/testing/run.d.ts +32 -2
  308. package/dist/testing/run.js +509 -25
  309. package/dist/trace-sanitization.d.ts +6 -0
  310. package/dist/trace-sanitization.js +68 -0
  311. package/dist/types.d.ts +899 -210
  312. package/dist/types.js +1 -0
  313. package/dist/typescript-module.d.ts +39 -0
  314. package/dist/typescript-module.js +72 -0
  315. package/package.json +52 -6
  316. package/src/auth-turn/index.ts +1 -1
  317. package/src/auth.ts +118 -0
  318. package/src/ceremonies/index.ts +189 -46
  319. package/src/cli/commands.ts +37 -0
  320. package/src/cli/create.ts +8 -2
  321. package/src/cli/deployment-intent.ts +364 -0
  322. package/src/cli/local-connection.ts +221 -0
  323. package/src/cli/migrate-deployment-intent.ts +1908 -0
  324. package/src/cli/migrate-operation-declaration.ts +3026 -0
  325. package/src/cli/migrate-operation-shape.ts +184 -0
  326. package/src/cli/migrate-provider-shape.ts +778 -0
  327. package/src/cli/resolver-runtime.ts +72 -0
  328. package/src/cli/templates/provider/.agents/skills/health-checks-and-fail-closed/SKILL.md.tpl +141 -23
  329. package/src/cli/templates/provider/Dockerfile.tpl +1 -1
  330. package/src/cli/templates/provider/README.md.tpl +41 -19
  331. package/src/cli/templates/provider/index.ts.tpl +6 -3
  332. package/src/cli/templates/provider/operations/ping.ts.tpl +4 -1
  333. package/src/cli/templates/provider/provider.json.tpl +6 -0
  334. package/src/config/loader.ts +774 -181
  335. package/src/contract-serialization.ts +5 -7
  336. package/src/contract-types.ts +12 -5
  337. package/src/contract.ts +24 -10
  338. package/src/declaration-validation.ts +376 -0
  339. package/src/define.ts +1105 -131
  340. package/src/dev.ts +13 -1
  341. package/src/engine.ts +390 -0
  342. package/src/error-observability.ts +64 -0
  343. package/src/error-resolution.ts +269 -0
  344. package/src/errors.ts +157 -0
  345. package/src/fixture-sanitization.ts +422 -0
  346. package/src/handle-meta.ts +143 -0
  347. package/src/handle.ts +694 -0
  348. package/src/health-scenario.ts +960 -0
  349. package/src/i18n/catalog.ts +23 -1
  350. package/src/i18n/error-messages.ts +255 -0
  351. package/src/i18n/index.ts +1 -0
  352. package/src/i18n/keys.ts +80 -6
  353. package/src/i18n/operation-locale-namespace.ts +10 -0
  354. package/src/index.ts +390 -23
  355. package/src/lint.ts +2975 -234
  356. package/src/native-address.ts +340 -0
  357. package/src/native-egress-policy.ts +358 -0
  358. package/src/observability.ts +51 -1
  359. package/src/provider.ts +207 -27
  360. package/src/runtime/auth-flow.ts +15 -0
  361. package/src/runtime/bounded-expiring-map.ts +67 -0
  362. package/src/runtime/browser-telemetry-binding.ts +92 -0
  363. package/src/runtime/browser-telemetry.ts +289 -0
  364. package/src/runtime/browser.ts +882 -99
  365. package/src/runtime/cache-telemetry.ts +247 -0
  366. package/src/runtime/cache.ts +258 -22
  367. package/src/runtime/capability-response.ts +53 -0
  368. package/src/runtime/capability-telemetry.ts +101 -0
  369. package/src/runtime/chrome149-header-order.ts +330 -0
  370. package/src/runtime/diagnostic-env-values.ts +56 -0
  371. package/src/runtime/diagnostic-env.ts +65 -0
  372. package/src/runtime/diagnostic-redactor.ts +668 -0
  373. package/src/runtime/egress-lease.ts +341 -0
  374. package/src/runtime/engine-mode.ts +233 -0
  375. package/src/runtime/env.ts +15 -1
  376. package/src/runtime/executor.ts +39 -32
  377. package/src/runtime/handle-wordlist.ts +266 -0
  378. package/src/runtime/handle.ts +1180 -0
  379. package/src/runtime/http-telemetry-binding.ts +162 -0
  380. package/src/runtime/http-telemetry-guard.ts +208 -0
  381. package/src/runtime/http-telemetry.ts +292 -0
  382. package/src/runtime/http.ts +896 -150
  383. package/src/runtime/insights.ts +2 -2
  384. package/src/runtime/instrumentation.ts +628 -28
  385. package/src/runtime/native-network-errors.ts +99 -0
  386. package/src/runtime/native-network.ts +1853 -0
  387. package/src/runtime/native-telemetry.ts +366 -0
  388. package/src/runtime/ocr-telemetry.ts +308 -0
  389. package/src/runtime/ocr.ts +564 -0
  390. package/src/runtime/otlp.ts +468 -21
  391. package/src/runtime/provider.ts +15 -0
  392. package/src/runtime/proxy-errors.ts +12 -4
  393. package/src/runtime/proxy-nodemaven.ts +222 -0
  394. package/src/runtime/proxy-retry-policy.ts +12 -1
  395. package/src/runtime/proxy-telemetry.ts +358 -103
  396. package/src/runtime/redirect-hop-headers.ts +71 -0
  397. package/src/runtime/redirects.ts +215 -0
  398. package/src/runtime/redis.ts +7 -2
  399. package/src/runtime/request-options.ts +728 -1
  400. package/src/runtime/request-telemetry.ts +375 -0
  401. package/src/runtime/resolver-config.ts +18 -0
  402. package/src/runtime/resolver-public.ts +44 -0
  403. package/src/runtime/resolver-runtime-options.ts +50 -0
  404. package/src/runtime/resolver-shared.ts +113 -0
  405. package/src/runtime/resolver-span-attributes.ts +139 -0
  406. package/src/runtime/resolver-telemetry.ts +362 -0
  407. package/src/runtime/resolver-usage.ts +99 -0
  408. package/src/runtime/resolver-vendors/bindings.ts +61 -0
  409. package/src/runtime/resolver-vendors/browser.ts +591 -0
  410. package/src/runtime/resolver-vendors/capsolver.ts +727 -0
  411. package/src/runtime/resolver-vendors/hosts.ts +81 -0
  412. package/src/runtime/resolver-vendors/hypersolutions.ts +480 -0
  413. package/src/runtime/resolver-vendors/twocaptcha.ts +555 -0
  414. package/src/runtime/resolver-vendors/types.ts +261 -0
  415. package/src/runtime/resolver.ts +1543 -0
  416. package/src/runtime/state-telemetry.ts +298 -0
  417. package/src/runtime/state.ts +435 -89
  418. package/src/runtime/stealth-akamai-sbsd.ts +207 -0
  419. package/src/runtime/stealth-cookies.ts +155 -0
  420. package/src/runtime/stealth-owned-headers.ts +67 -0
  421. package/src/runtime/stealth-telemetry.ts +309 -0
  422. package/src/runtime/stealth.ts +2275 -372
  423. package/src/runtime/stt-telemetry.ts +282 -0
  424. package/src/runtime/stt.ts +96 -91
  425. package/src/runtime/timeout.ts +18 -0
  426. package/src/runtime/trace-config.ts +78 -0
  427. package/src/runtime/trace.ts +257 -35
  428. package/src/runtime-boundary-lint.ts +707 -0
  429. package/src/schema.ts +80 -2
  430. package/src/serve.ts +6 -1
  431. package/src/server/error-observability.ts +1 -0
  432. package/src/server/error-stack-frames.ts +214 -0
  433. package/src/server/index.ts +184 -2
  434. package/src/server/runtime-diagnostics.ts +522 -0
  435. package/src/server/sdk-version.ts +22 -0
  436. package/src/server/self-test-input-tokens.ts +29 -14
  437. package/src/server/self-test-redaction.ts +10 -40
  438. package/src/server/self-test.ts +205 -89
  439. package/src/server/sensitive-values.ts +211 -0
  440. package/src/server/serve-implementation.ts +4596 -0
  441. package/src/server/serve.ts +1 -1685
  442. package/src/server/state-backend-report.ts +185 -0
  443. package/src/server/trace-output.ts +189 -0
  444. package/src/server/types.ts +34 -1
  445. package/src/stateful/README.md +146 -0
  446. package/src/stateful/errors.ts +35 -0
  447. package/src/stateful/http-provider-event-emitter.ts +314 -0
  448. package/src/stateful/http-session-owner-registry.ts +306 -0
  449. package/src/stateful/index.ts +18 -0
  450. package/src/stateful/provider-event-delivery-failures.ts +80 -0
  451. package/src/stateful/provider-event-pipeline-metrics.ts +95 -0
  452. package/src/stateful/provider-event-pipeline.ts +61 -0
  453. package/src/stateful/provider-events.ts +462 -0
  454. package/src/stateful/session-key.ts +111 -0
  455. package/src/stateful/stateful-provider-adapter-context.ts +59 -0
  456. package/src/stateful/stateful-provider-adapter-metrics.ts +48 -0
  457. package/src/stateful/stateful-provider-adapter.ts +562 -0
  458. package/src/stateful/stateful-provider-observability.ts +261 -0
  459. package/src/stateful/stateful-provider-owner-forwarder.ts +310 -0
  460. package/src/stateful/stateful-provider-runtime-context.ts +96 -0
  461. package/src/stateful/stateful-provider-runtime-executor.ts +96 -0
  462. package/src/stateful/stateful-provider-session-routing.ts +546 -0
  463. package/src/stateful/stateful-provider-session-runtime.ts +403 -0
  464. package/src/stateful-signing.ts +46 -0
  465. package/src/stealth/profiles.ts +212 -231
  466. package/src/stream-evidence.ts +988 -0
  467. package/src/stream.ts +8 -1
  468. package/src/testing/index.ts +10 -1
  469. package/src/testing/run.ts +685 -19
  470. package/src/trace-sanitization.ts +110 -0
  471. package/src/types.ts +1014 -273
  472. package/src/typescript-module.ts +100 -0
  473. package/dist/choice-token.d.ts +0 -24
  474. package/dist/choice-token.js +0 -74
  475. package/dist/runtime/choice.d.ts +0 -15
  476. package/dist/runtime/choice.js +0 -413
  477. package/src/choice-token.ts +0 -165
  478. package/src/runtime/choice.ts +0 -686
@@ -0,0 +1,185 @@
1
+ import {
2
+ providerCacheRedisResolutionFromEnv,
3
+ type ProviderRedisUrlResolution,
4
+ providerStateRedisResolutionFromEnv,
5
+ } from "../config/loader.js";
6
+
7
+ /**
8
+ * What a provider store resolved to at boot.
9
+ *
10
+ * `endpoint` is deliberately host and port only: the URL can carry a password
11
+ * (`redis://:secret@host:6379`), and the diagnostic inventory already treats
12
+ * those credential components — and only those — as sensitive
13
+ * (`collectDiagnosticSensitiveValues`, `urlCredentialComponents(url, {
14
+ * includePathAndQuery: false })`). A URL that does not parse contributes no
15
+ * endpoint at all rather than a redacted-looking fragment of itself.
16
+ */
17
+ export type ProviderStoreBackendReport = {
18
+ /**
19
+ * `redis` when a URL resolved, `memory` for the in-process fallback,
20
+ * `unsupported` when state has no backend and every call fails closed,
21
+ * `injected` when the host handed the server a store object.
22
+ */
23
+ readonly backend: "redis" | "memory" | "unsupported" | "injected";
24
+ /** Env name that supplied the Redis URL. Present only for `redis`. */
25
+ readonly envName?: string;
26
+ /**
27
+ * `host:port` of the resolved Redis. Never includes credentials, path or
28
+ * query. Absent when the URL does not parse, or when its query carries an
29
+ * ioredis option that moves the endpoint (`path`, `port`, `host`, `family`)
30
+ * so the authority is not where the client connects — see
31
+ * `state_redis_url_ambiguous_endpoint`.
32
+ */
33
+ readonly endpoint?: string;
34
+ /** URL scheme, e.g. `redis` or `rediss`. Present only for `redis`. */
35
+ readonly scheme?: string;
36
+ /** True when the URL came from a shared fallback env rather than the store's own. */
37
+ readonly fallback?: boolean;
38
+ };
39
+
40
+ /**
41
+ * One line per process boot naming the stores the provider resolved. Without
42
+ * it, a provider silently riding the cache Redis for its state is
43
+ * indistinguishable from one on a durable instance, from outside the pod and
44
+ * from the pod's own logs (apifuse#2302, the reason apifuse#2144 could only be
45
+ * verified by inference from the Deployment spec).
46
+ */
47
+ export type ProviderStateBackendLogEvent = {
48
+ /** `warn` when a warning was raised, otherwise `info`. */
49
+ readonly level: "info" | "warn";
50
+ readonly event: "provider_state_backend";
51
+ readonly providerId: string;
52
+ readonly state: ProviderStoreBackendReport;
53
+ readonly cache: ProviderStoreBackendReport;
54
+ readonly sdkVersion: string;
55
+ /**
56
+ * Non-fatal findings, e.g. `state_redis_url_fallback` (the state store is
57
+ * sharing an instance provisioned for something else),
58
+ * `state_redis_url_unparsed`, or `state_redis_url_ambiguous_endpoint` (the
59
+ * URL's query carries an ioredis option that moves the endpoint, so the
60
+ * authority is not reported as the endpoint). Absent when the resolution
61
+ * was unambiguous.
62
+ */
63
+ readonly warnings?: readonly string[];
64
+ };
65
+
66
+ /**
67
+ * Whether ioredis' own URL parsing would move the endpoint away from the
68
+ * authority this function can see. `createProviderRedisClient` hands the raw
69
+ * URL to `new Redis(url, …)`, and `parseURL` ends with
70
+ * `defaults(result, queryOptions)` — lodash `defaults`, so a query key only
71
+ * applies where the authority supplied nothing:
72
+ *
73
+ * - `path` is never derived from the authority of a `redis://` URL (that
74
+ * pathname is the db index), so `?path=` always applies — and
75
+ * `StandaloneConnector` connects to `options.path` INSTEAD of host/port.
76
+ * The client is then on a Unix socket the authority says nothing about.
77
+ * - `port` applies only when the URL carries no explicit port.
78
+ * - `host` never applies here: we return early unless `parsed.hostname` is
79
+ * set, so `result.host` is always already populated.
80
+ * - `family` selects an address family; it does not move `host:port`.
81
+ *
82
+ * Verified against the pinned ioredis 5.11.1. In those cases the endpoint is
83
+ * WITHHELD and the ambiguity named, rather than reported as the authority — a
84
+ * diagnostic whose whole job is to answer "which Redis is this provider on"
85
+ * must not answer it wrongly. The query is never echoed: it can carry a
86
+ * password, which is why `endpoint` is host-and-port only to begin with.
87
+ */
88
+ function queryMovesEndpoint(parsed: URL): boolean {
89
+ if (parsed.searchParams.has("path")) return true;
90
+ return parsed.searchParams.has("port") && parsed.port === "";
91
+ }
92
+
93
+ function redisEndpoint(url: string): {
94
+ endpoint?: string;
95
+ scheme?: string;
96
+ ambiguous?: boolean;
97
+ } {
98
+ let parsed: URL;
99
+ try {
100
+ parsed = new URL(url);
101
+ } catch {
102
+ return {};
103
+ }
104
+ // No authority means this is not the `redis://host:port` shape at all (e.g.
105
+ // a bare `host:port`, which parses as a scheme). Report nothing rather than
106
+ // a fragment of a string whose parts we have not identified.
107
+ if (!parsed.hostname) return {};
108
+ const scheme = parsed.protocol.replace(/:$/, "");
109
+ if (queryMovesEndpoint(parsed)) return { scheme, ambiguous: true };
110
+ return {
111
+ scheme,
112
+ endpoint: parsed.port ? `${parsed.hostname}:${parsed.port}` : parsed.hostname,
113
+ };
114
+ }
115
+
116
+ function redisReport(resolution: ProviderRedisUrlResolution): {
117
+ report: ProviderStoreBackendReport;
118
+ parsed: boolean;
119
+ ambiguous: boolean;
120
+ } {
121
+ const { endpoint, scheme, ambiguous } = redisEndpoint(resolution.url);
122
+ return {
123
+ parsed: endpoint !== undefined || ambiguous === true,
124
+ ambiguous: ambiguous === true,
125
+ report: {
126
+ backend: "redis",
127
+ envName: resolution.envName,
128
+ ...(endpoint === undefined ? {} : { endpoint }),
129
+ ...(scheme === undefined ? {} : { scheme }),
130
+ ...(resolution.fallback ? { fallback: true } : {}),
131
+ },
132
+ };
133
+ }
134
+
135
+ /**
136
+ * Build the boot event from the same env precedence the stores themselves use
137
+ * (`providerStateRedisResolutionFromEnv` / `providerCacheRedisResolutionFromEnv`),
138
+ * so the line can never describe a backend other than the one in use.
139
+ */
140
+ export function providerStateBackendLogEvent(input: {
141
+ readonly providerId: string;
142
+ readonly sdkVersion: string;
143
+ /** The host passed an explicit state store, so no env resolution happened. */
144
+ readonly injectedState: boolean;
145
+ /** Mirrors `createProviderRuntimeStateFromEnv({ allowMemoryFallback })`. */
146
+ readonly allowMemoryFallback: boolean;
147
+ }): ProviderStateBackendLogEvent {
148
+ const warnings: string[] = [];
149
+ let state: ProviderStoreBackendReport;
150
+ if (input.injectedState) {
151
+ state = { backend: "injected" };
152
+ } else {
153
+ const resolution = providerStateRedisResolutionFromEnv();
154
+ if (resolution) {
155
+ const { report, parsed, ambiguous } = redisReport(resolution);
156
+ state = report;
157
+ if (!parsed) warnings.push("state_redis_url_unparsed");
158
+ if (ambiguous) warnings.push("state_redis_url_ambiguous_endpoint");
159
+ if (resolution.fallback) warnings.push("state_redis_url_fallback");
160
+ } else {
161
+ state = { backend: input.allowMemoryFallback ? "memory" : "unsupported" };
162
+ }
163
+ }
164
+
165
+ const cacheResolution = providerCacheRedisResolutionFromEnv();
166
+ let cache: ProviderStoreBackendReport;
167
+ if (cacheResolution) {
168
+ const { report, parsed, ambiguous } = redisReport(cacheResolution);
169
+ cache = report;
170
+ if (!parsed) warnings.push("cache_redis_url_unparsed");
171
+ if (ambiguous) warnings.push("cache_redis_url_ambiguous_endpoint");
172
+ } else {
173
+ cache = { backend: "memory" };
174
+ }
175
+
176
+ return {
177
+ level: warnings.length > 0 ? "warn" : "info",
178
+ event: "provider_state_backend",
179
+ providerId: input.providerId,
180
+ state,
181
+ cache,
182
+ sdkVersion: input.sdkVersion,
183
+ ...(warnings.length === 0 ? {} : { warnings }),
184
+ };
185
+ }
@@ -0,0 +1,189 @@
1
+ import { isSensitiveFixtureKey, REDACTED_FIXTURE_VALUE } from "../fixture-sanitization.js";
2
+ import {
3
+ type DiagnosticRedactor,
4
+ redactedKeyAllocator,
5
+ isRedactedKey,
6
+ REDACTION_FAILED,
7
+ redactDiagnosticText,
8
+ } from "../runtime/diagnostic-redactor.js";
9
+ import {
10
+ OTEL_EXPORTER_OTLP_ENDPOINT,
11
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
12
+ type OTLPExportOptions,
13
+ type OTLPExportResolution,
14
+ type OTLPResourceResolution,
15
+ resolveOTLPExportOptions,
16
+ resolveOTLPResourceAttributes,
17
+ } from "../runtime/otlp.js";
18
+ import {
19
+ type CreateTraceContextOptions,
20
+ resolveTraceContextOptions,
21
+ type Span,
22
+ } from "../runtime/trace.js";
23
+ import {
24
+ sanitizeSpanForOutput,
25
+ sanitizeSpanNameForOutput,
26
+ sanitizeTraceAttributes,
27
+ } from "../trace-sanitization.js";
28
+ import type { TraceConfig } from "../types.js";
29
+
30
+ type EnvLike = Record<string, string | undefined>;
31
+
32
+ const TRACE_RESOURCE_ATTRIBUTE_SANITIZER = Symbol.for(
33
+ "@apifuse/provider-sdk/runtime/trace-resource-attribute-sanitizer",
34
+ );
35
+
36
+ type ResourceAttributesWithSanitizer = Record<string, string> & {
37
+ [TRACE_RESOURCE_ATTRIBUTE_SANITIZER]?: (
38
+ attributes: Record<string, string>,
39
+ ) => Record<string, string>;
40
+ };
41
+
42
+ // Warn once per environment object: process.env in production, each injected env in tests.
43
+ const warnedEnvironments = new WeakSet<EnvLike>();
44
+ const warnedResourceEnvironments = new WeakSet<EnvLike>();
45
+
46
+ function warnDiscardedResourceAttributes(env: EnvLike, resolution: OTLPResourceResolution): void {
47
+ if (resolution.discarded.length === 0 || warnedResourceEnvironments.has(env)) return;
48
+ warnedResourceEnvironments.add(env);
49
+ console.warn(
50
+ `[apifuse] ${resolution.discarded.join(", ")} could not be parsed as an OTel key=value list and was ignored.`,
51
+ );
52
+ }
53
+
54
+ function warnExportDisabled(
55
+ env: EnvLike,
56
+ resolution: Exclude<OTLPExportResolution, { status: "resolved" }>,
57
+ ): void {
58
+ if (warnedEnvironments.has(env)) return;
59
+ warnedEnvironments.add(env);
60
+ console.warn(
61
+ resolution.status === "unconfigured"
62
+ ? `[apifuse] OTLP trace export is enabled but no endpoint is configured; set ${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT} or ${OTEL_EXPORTER_OTLP_ENDPOINT}. Trace export is disabled.`
63
+ : `[apifuse] OTLP trace export is enabled but ${resolution.source} ${resolution.reason}. Trace export is disabled.`,
64
+ );
65
+ }
66
+
67
+ function resolveServerOTLPExportOptions(
68
+ config: TraceConfig,
69
+ env: EnvLike,
70
+ ): OTLPExportOptions | undefined {
71
+ const resolution = resolveOTLPExportOptions(
72
+ {
73
+ endpoint: config.otlp?.endpoint ?? config.endpoint,
74
+ headers: config.otlp?.headers,
75
+ timeout: config.otlp?.timeout,
76
+ },
77
+ env,
78
+ );
79
+ if (resolution.status === "resolved") return resolution.options;
80
+ warnExportDisabled(env, resolution);
81
+ return undefined;
82
+ }
83
+
84
+ /**
85
+ * Per-request attributes carry client-supplied values (request_id) and get the full attribute
86
+ * sanitizer, exactly as on the console path. Operator-configured attributes from the process
87
+ * environment are identifiers rather than request data: their values are kept, with control
88
+ * characters neutralized, length bounded, and secret-named keys redacted.
89
+ */
90
+ function resolveExportResourceAttributes(
91
+ requestAttributes: Record<string, string>,
92
+ env: EnvLike,
93
+ redact?: DiagnosticRedactor,
94
+ ): {
95
+ attributes: Record<string, string>;
96
+ sanitize: (attributes: Record<string, string>) => Record<string, string>;
97
+ } {
98
+ const resolution = resolveOTLPResourceAttributes({}, env);
99
+ warnDiscardedResourceAttributes(env, resolution);
100
+ const operatorAttributes = resolution.attributes;
101
+ const requestKeys = new Set(Object.keys(requestAttributes));
102
+ return {
103
+ // Keep the raw snapshot private until export. A credential registered after
104
+ // trace creation must be matched before any key or value is bounded.
105
+ attributes: { ...operatorAttributes, ...requestAttributes },
106
+ sanitize(attributes) {
107
+ const nextKey = redactedKeyAllocator(Object.keys(attributes));
108
+ const sanitizedOperatorAttributes: Record<string, string> = {};
109
+ const rawRequestAttributes: Record<string, string> = {};
110
+ for (const [key, value] of Object.entries(attributes)) {
111
+ const unchangedOperatorValue = !requestKeys.has(key) && operatorAttributes[key] === value;
112
+ if (unchangedOperatorValue) {
113
+ const redactedKey = isRedactedKey(key) ? key : redactDiagnosticText(key, redact);
114
+ const keyChanged = redactedKey !== key;
115
+ const sanitizedKey = keyChanged ? nextKey() : sanitizeSpanNameForOutput(key);
116
+ sanitizedOperatorAttributes[sanitizedKey] = keyChanged
117
+ ? redactedKey === REDACTION_FAILED
118
+ ? REDACTION_FAILED
119
+ : REDACTED_FIXTURE_VALUE
120
+ : isSensitiveFixtureKey(key)
121
+ ? REDACTED_FIXTURE_VALUE
122
+ : sanitizeSpanNameForOutput(value, redact);
123
+ } else {
124
+ rawRequestAttributes[key] = value;
125
+ }
126
+ }
127
+ const sanitizedRequestAttributes = Object.fromEntries(
128
+ Object.entries(
129
+ sanitizeTraceAttributes(
130
+ rawRequestAttributes,
131
+ redact,
132
+ Object.keys(sanitizedOperatorAttributes),
133
+ ),
134
+ ).map(([key, value]) => [key, String(value)]),
135
+ );
136
+ return { ...sanitizedOperatorAttributes, ...sanitizedRequestAttributes };
137
+ },
138
+ };
139
+ }
140
+
141
+ /** Server-only trace output policy. Shared programmatic trace callers stay in-memory. */
142
+ export function resolveServerTraceContextOptions(
143
+ config: TraceConfig,
144
+ resourceAttributes: Record<string, string>,
145
+ env: EnvLike = process.env,
146
+ redact?: DiagnosticRedactor,
147
+ ): CreateTraceContextOptions {
148
+ const resolved = resolveTraceContextOptions(config);
149
+ const outputEnabled = config.enabled !== false && config.exporter !== "none";
150
+ const consoleHook =
151
+ outputEnabled && (config.exporter === "console" || config.exporter === "json")
152
+ ? (span: Span) =>
153
+ console.log(JSON.stringify(sanitizeSpanForOutput(span, resourceAttributes, redact)))
154
+ : undefined;
155
+ const onSpan =
156
+ consoleHook && resolved.onSpan
157
+ ? (span: Span) => {
158
+ consoleHook(span);
159
+ resolved.onSpan?.(span);
160
+ }
161
+ : (consoleHook ?? resolved.onSpan);
162
+ const exportOptions =
163
+ outputEnabled && config.exporter === "otlp"
164
+ ? resolveServerOTLPExportOptions(config, env)
165
+ : undefined;
166
+ const exportResources = exportOptions
167
+ ? resolveExportResourceAttributes(resourceAttributes, env, redact)
168
+ : undefined;
169
+ if (exportResources) {
170
+ Object.defineProperty(
171
+ exportResources.attributes as ResourceAttributesWithSanitizer,
172
+ TRACE_RESOURCE_ATTRIBUTE_SANITIZER,
173
+ { value: exportResources.sanitize },
174
+ );
175
+ }
176
+
177
+ return {
178
+ maxSpans: resolved.maxSpans,
179
+ onSpan,
180
+ ...(redact ? { redact } : {}),
181
+ ...(exportOptions
182
+ ? {
183
+ exportOptions,
184
+ resourceAttributes: exportResources?.attributes,
185
+ sanitizeSpanForExport: (span: Span) => sanitizeSpanForOutput(span, undefined, redact),
186
+ }
187
+ : {}),
188
+ };
189
+ }
@@ -1,8 +1,15 @@
1
1
  import { z } from "zod";
2
+ import { PROVIDER_ERROR_SOURCES } from "../observability.js";
2
3
 
3
4
  import { HttpRetryPreset } from "../types.js";
4
5
 
5
- export const ConnectionModeSchema = z.enum(["oauth2", "credentials", "platform-managed", "none"]);
6
+ export const ConnectionModeSchema = z.enum([
7
+ "oauth2",
8
+ "oauth2_proxied",
9
+ "credentials",
10
+ "platform-managed",
11
+ "none",
12
+ ]);
6
13
 
7
14
  export const OperationConnectionSchema = z.object({
8
15
  id: z.string(),
@@ -18,6 +25,13 @@ export const OperationRequestSchema = z.object({
18
25
  input: z.record(z.string(), z.unknown()),
19
26
  connectionId: z.string().optional(),
20
27
  connection: OperationConnectionSchema.optional(),
28
+ /**
29
+ * Gateway-asserted principal scope: the organization id for customer
30
+ * subjects, the service-account id for platform service accounts. Absent
31
+ * on direct calls and self-test. Trusted exactly like `connectionId`; it is
32
+ * never derived from caller headers or `input`.
33
+ */
34
+ tenantId: z.string().optional(),
21
35
  headers: z.record(z.string(), z.string()).optional(),
22
36
  trace: z.record(z.string(), z.string()).optional(),
23
37
  });
@@ -26,6 +40,11 @@ export const ErrorEnvelopeSchema = z.object({
26
40
  code: z.string(),
27
41
  message: z.string(),
28
42
  requestId: z.string().optional(),
43
+ retryable: z.boolean(),
44
+ // Who stopped the request (honest-provider-error-contract); optional so
45
+ // older peers (stateful forwarding owners) remain parseable. Derived from
46
+ // the PROVIDER_ERROR_SOURCES registry so the enum cannot drift.
47
+ source: z.enum(PROVIDER_ERROR_SOURCES).optional(),
29
48
  fix: z.string().optional(),
30
49
  details: z.unknown().optional(),
31
50
  });
@@ -81,12 +100,26 @@ export const AuthFlowRequestSchema = z.object({
81
100
  headers: z.record(z.string(), z.string()).optional(),
82
101
  input: z.record(z.string(), z.unknown()).optional(),
83
102
  context: z.record(z.string(), z.unknown()).optional(),
103
+ /** Opaque engine state. This is never projected into FlowContext or provider contextPatch. */
104
+ engine: z
105
+ .object({
106
+ egressLease: z.string().min(1).max(16_384).optional(),
107
+ })
108
+ .strict()
109
+ .optional(),
84
110
  connection: OperationConnectionSchema.optional(),
85
111
  });
86
112
 
87
113
  export const AuthFlowSuccessResponseSchema = z.object({
88
114
  data: z.unknown(),
89
115
  contextPatch: z.record(z.string(), z.unknown().nullable()).optional(),
116
+ /** Opaque engine state to carry verbatim to the next auth turn. */
117
+ engine: z
118
+ .object({
119
+ egressLease: z.string().min(1).max(16_384).optional(),
120
+ })
121
+ .strict()
122
+ .optional(),
90
123
  });
91
124
 
92
125
  export const AuthFlowErrorResponseSchema = OperationErrorResponseSchema;
@@ -0,0 +1,146 @@
1
+ # Stateful module compatibility note
2
+
3
+ The `@apifuse/provider-sdk/stateful` entry point is new and unreleased. Its initial contract includes
4
+ the following compatibility-sensitive behavior:
5
+
6
+ - Session identifiers use the branded `SessionKey` returned by `buildSessionKey`.
7
+ `parseSessionKey` returns `SessionKeyParts`; validate and brand an external string with
8
+ `buildSessionKey(parseSessionKey(value))`. Registry inputs, routing requests, event owner fences,
9
+ and release APIs no longer accept arbitrary strings. A decoded `SessionOwnerRecord.sessionKey`
10
+ remains a string and must be checked where external data enters trusted SDK code (a trust
11
+ boundary).
12
+ - Adapters declare `policy.concurrency` (`serialize` or bounded/unbounded `parallel`) and
13
+ `policy.reconnect` (`resume`, `recreate`, or `unsupported`). `restore`, `snapshot`, and `health`
14
+ are optional; a declared `snapshot` must be paired with the manager's `checkpointStore`.
15
+ - Code in the process hosting the adapter (the provider pod) publishes through
16
+ `ProviderEventPublisher`; persistent services that survive provider-pod restarts (durable
17
+ platform code) implement `ProviderEventPipeline`. An adapter's
18
+ `subscribe(ctx, session, publish)` callback accepts only an event. The session manager, not the
19
+ adapter, binds the registry's current write authorization (the authoritative
20
+ `{ sessionKey, generation, ownerPodId, ownerEndpoint }` fence) before calling the publisher.
21
+ Adapters must not construct or cache owner fences themselves.
22
+ - `subscribe` must return a disposer. The manager runs it before checkpointing and closing a
23
+ session. `health()` and `reconcileWrite()` use the same per-session concurrency scheduler and
24
+ optional ownership validation semantics as invocation.
25
+ - `HttpProviderEventEmitter.flush(timeoutMs)` resolves to
26
+ `{ delivered: number, failed: number, pending: number }`. Counts are cumulative for the emitter's
27
+ lifetime; `pending` is the buffer remaining when the flush returns.
28
+ - `serve()` resolves to a `ProviderServerHandle` with `port` and idempotent `close({ timeoutMs? })`.
29
+ Close stops listeners, runs shutdown hooks in declaration order, and enforces the configured
30
+ timeout. Signal-enabled handles share one process handler per signal; a signal closes every
31
+ registered server before it is re-raised. Closing the last handle removes the shared handlers.
32
+ - `ProviderServerStatefulForwardEnvelope` is strict. Its owner fence is flattened into
33
+ `sessionKey`, `ownerPodId`, and `generation`; a nested `owner` object is not accepted. The
34
+ envelope also carries operation/session identity, `sourcePodId`, `forwardedAt`, optional
35
+ `idempotencyKey`, optional ISO `deadlineAt`, and the nested `operationRequest`. Unknown or
36
+ malformed fields fail closed, and the owner-side executor receives `deadlineAt` on its request.
37
+ - Stateful forwarding is configured as a pair: `internalOperationExecutor` requires
38
+ `statefulForwarding`, and `statefulForwarding` requires an `internalOperationExecutor`.
39
+ `statefulForwarding` supplies the signing secret and `validateOwnerFence`; it may also set
40
+ `maxSkewMs` and `replayCacheMaxEntries`. Replay-cache capacity returns HTTP 503 with
41
+ `Retry-After`; fail-closed nonce handling means invalid, replayed, or untrackable nonces are
42
+ rejected instead of allowing an unverifiable request.
43
+ - Stateful signatures bind the method, route, timestamp, nonce, and exact body. Forwarding also
44
+ rejects provider/source mismatches, stale owner fences, nonce replay, and request-scoped files.
45
+
46
+ ## Minimal composition
47
+
48
+ Inside the module that defines your `provider`, the following wires an adapter, session manager,
49
+ router, signed owner forwarding, and graceful shutdown. Replace the environment variable names and
50
+ the service-account mapping with your deployment's values.
51
+
52
+ ```ts
53
+ import {
54
+ buildSessionKey,
55
+ createStatefulOwnerFenceValidator,
56
+ HttpSessionOwnerRegistry,
57
+ HttpStatefulOwnerForwarder,
58
+ parseSessionKey,
59
+ statefulForwardingContextFromProviderRequest,
60
+ StatefulProviderSessionManager,
61
+ StatefulSessionRouter,
62
+ type StatefulProviderAdapter,
63
+ withStatefulLocalProviderContext,
64
+ } from "@apifuse/provider-sdk/stateful";
65
+ import { serve, type ProviderServerOperationExecutor } from "@apifuse/provider-sdk/server";
66
+
67
+ type Session = { closed: boolean };
68
+
69
+ const adapter = {
70
+ providerId: provider.id,
71
+ policy: { concurrency: { mode: "serialize" }, reconnect: "recreate" },
72
+ connect: async () => ({ closed: false }),
73
+ invoke: async (_ctx, _session, request) => ({ output: request.input }),
74
+ close: async (_ctx, session) => {
75
+ session.closed = true;
76
+ },
77
+ } satisfies StatefulProviderAdapter<Session>;
78
+
79
+ const registry = new HttpSessionOwnerRegistry({
80
+ baseUrl: process.env.STATEFUL_CONTROL_PLANE_URL as string,
81
+ secret: process.env.STATEFUL_CONTROL_PLANE_SECRET as string,
82
+ });
83
+ const manager = new StatefulProviderSessionManager({
84
+ adapter,
85
+ poolPolicy: { maxSessions: 100, idleTimeoutMs: "unlimited", maxLifetimeMs: "unlimited" },
86
+ });
87
+ const currentPod = {
88
+ podId: process.env.POD_ID as string,
89
+ endpoint: process.env.POD_ENDPOINT as string,
90
+ };
91
+ const router = new StatefulSessionRouter({
92
+ currentPod,
93
+ registry,
94
+ forwarder: new HttpStatefulOwnerForwarder({
95
+ currentPodId: currentPod.podId,
96
+ secret: process.env.STATEFUL_FORWARDING_SECRET as string,
97
+ }),
98
+ executor: manager,
99
+ leaseDurationMs: 30_000,
100
+ });
101
+
102
+ const executeStateful: ProviderServerOperationExecutor = async ({
103
+ ctx,
104
+ request,
105
+ operationId,
106
+ internalStatefulForward,
107
+ }) => {
108
+ const keyParts = internalStatefulForward
109
+ ? parseSessionKey(internalStatefulForward.sessionKey)
110
+ : {
111
+ providerId: provider.id,
112
+ serviceAccountId: request.connection?.externalRef as string,
113
+ connectionId: (request.connection?.id ?? request.connectionId) as string,
114
+ };
115
+ const result = await router.route({
116
+ requestId: request.requestId,
117
+ sessionKey: buildSessionKey(keyParts),
118
+ providerId: provider.id,
119
+ operationId,
120
+ connectionId: keyParts.connectionId,
121
+ serviceAccountId: keyParts.serviceAccountId,
122
+ input: request.input,
123
+ ...(request.deadlineAt ? { deadlineAt: request.deadlineAt } : {}),
124
+ runtimeContext: withStatefulLocalProviderContext(
125
+ ctx,
126
+ statefulForwardingContextFromProviderRequest(request),
127
+ ),
128
+ });
129
+ return result.output;
130
+ };
131
+
132
+ await serve(provider, {
133
+ operationExecutor: executeStateful,
134
+ internalOperationExecutor: executeStateful,
135
+ statefulForwarding: {
136
+ secret: process.env.STATEFUL_FORWARDING_SECRET as string,
137
+ validateOwnerFence: createStatefulOwnerFenceValidator(registry),
138
+ },
139
+ shutdown: {
140
+ hooks: [
141
+ () => manager.closeAll("server-shutdown"),
142
+ () => router.release(),
143
+ ],
144
+ },
145
+ });
146
+ ```
@@ -0,0 +1,35 @@
1
+ export type StatefulControlPlaneOperation = "resolve" | "acquire" | "renew" | "release";
2
+
3
+ export class StatefulRoutingDeadlineError extends Error {
4
+ readonly requestId: string;
5
+ readonly deadlineAt: string;
6
+
7
+ constructor(requestId: string, deadlineAt: string) {
8
+ super(`Stateful operation request ${requestId} deadline has expired.`);
9
+ this.name = "StatefulRoutingDeadlineError";
10
+ this.requestId = requestId;
11
+ this.deadlineAt = deadlineAt;
12
+ }
13
+ }
14
+
15
+ export class StatefulControlPlaneError extends Error {
16
+ readonly code: string;
17
+ readonly operation: StatefulControlPlaneOperation;
18
+ readonly status?: number;
19
+ readonly cause?: unknown;
20
+
21
+ constructor(input: {
22
+ readonly code: string;
23
+ readonly message: string;
24
+ readonly operation: StatefulControlPlaneOperation;
25
+ readonly status?: number;
26
+ readonly cause?: unknown;
27
+ }) {
28
+ super(input.message);
29
+ this.name = "StatefulControlPlaneError";
30
+ this.code = input.code;
31
+ this.operation = input.operation;
32
+ this.status = input.status;
33
+ this.cause = input.cause;
34
+ }
35
+ }