@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
@@ -0,0 +1,287 @@
1
+ import { makeStatefulProviderCloseContext, makeStatefulProviderSessionContext, } from "./stateful-provider-adapter-context.js";
2
+ import { emitStatefulSessionInvalidatedMetric, observeStatefulSessionOperationDuration, } from "./stateful-provider-adapter-metrics.js";
3
+ import { NOOP_STATEFUL_PROVIDER_METRIC_EMITTER, } from "./stateful-provider-observability.js";
4
+ import { PodLocalSessionPool } from "./stateful-provider-session-runtime.js";
5
+ export class StatefulSessionInvalidatedError extends Error {
6
+ name = "StatefulSessionInvalidatedError";
7
+ reason;
8
+ retryable;
9
+ constructor(message, options) {
10
+ super(message);
11
+ this.reason = options.reason;
12
+ this.retryable = options.retryable ?? false;
13
+ }
14
+ }
15
+ const STATEFUL_SESSION_ESTABLISHMENT_FAILURE = Symbol.for("@apifuse/provider-sdk/stateful/session-establishment-failure@1");
16
+ function markStatefulSessionEstablishmentFailure(error) {
17
+ if ((typeof error === "object" && error !== null) || typeof error === "function") {
18
+ try {
19
+ Object.defineProperty(error, STATEFUL_SESSION_ESTABLISHMENT_FAILURE, {
20
+ value: true,
21
+ enumerable: false,
22
+ });
23
+ return error;
24
+ }
25
+ catch { }
26
+ }
27
+ const wrapped = new Error("Stateful session establishment failed.", { cause: error });
28
+ Object.defineProperty(wrapped, STATEFUL_SESSION_ESTABLISHMENT_FAILURE, { value: true });
29
+ return wrapped;
30
+ }
31
+ export class StatefulProviderSessionManager {
32
+ #adapter;
33
+ #pool;
34
+ #checkpointStore;
35
+ #eventPublisher;
36
+ #clock;
37
+ #metricEmitter;
38
+ #eventDisposers = new Map();
39
+ #eventOwnerFences = new Map();
40
+ #parallelLimiters = new Map();
41
+ constructor(options) {
42
+ validateAdapterConfiguration(options);
43
+ this.#adapter = options.adapter;
44
+ this.#checkpointStore = options.checkpointStore;
45
+ this.#eventPublisher = options.eventPublisher;
46
+ this.#clock = options.clock ?? (() => new Date());
47
+ this.#metricEmitter = options.metricEmitter ?? NOOP_STATEFUL_PROVIDER_METRIC_EMITTER;
48
+ this.#pool = new PodLocalSessionPool(options.poolPolicy, (session, reason) => this.closeManagedSession(session, reason));
49
+ }
50
+ async invoke(owner, request, signal, validateOwnership) {
51
+ const startedAt = this.#clock().getTime();
52
+ const run = async () => {
53
+ const managedSession = await this.getOrCreate(owner, request, signal, validateOwnership);
54
+ const validatedOwner = await this.validatePooledOwnership(owner, request.sessionKey, signal, validateOwnership);
55
+ const ctx = makeStatefulProviderSessionContext(this.#adapter.providerId, validatedOwner, request, signal);
56
+ try {
57
+ const result = await this.#adapter.invoke(ctx, managedSession.value, request);
58
+ this.observeDuration(request, owner, startedAt);
59
+ return result;
60
+ }
61
+ catch (error) {
62
+ if (!(error instanceof StatefulSessionInvalidatedError))
63
+ throw error;
64
+ emitStatefulSessionInvalidatedMetric({
65
+ metricEmitter: this.#metricEmitter,
66
+ request,
67
+ owner,
68
+ reason: error.reason,
69
+ });
70
+ await this.#pool.invalidate(owner.sessionKey, error.reason);
71
+ if (!error.retryable || this.#adapter.policy.reconnect === "unsupported")
72
+ throw error;
73
+ const reconnected = await this.getOrCreate(owner, request, signal, validateOwnership);
74
+ const revalidatedOwner = await this.validatePooledOwnership(owner, request.sessionKey, signal, validateOwnership);
75
+ const reconnectedCtx = makeStatefulProviderSessionContext(this.#adapter.providerId, revalidatedOwner, request, signal);
76
+ const result = await this.#adapter.invoke(reconnectedCtx, reconnected.value, request);
77
+ this.observeDuration(request, owner, startedAt);
78
+ return result;
79
+ }
80
+ };
81
+ return this.schedule(owner.sessionKey, run);
82
+ }
83
+ executeLocal(request, owner, signal, validateOwnership) {
84
+ return this.invoke(owner, request, signal, validateOwnership);
85
+ }
86
+ async health(owner, request, signal, validateOwnership) {
87
+ if (!this.#adapter.health) {
88
+ throw new Error(`Stateful provider adapter "${this.#adapter.providerId}" has no health hook.`);
89
+ }
90
+ return this.schedule(owner.sessionKey, async () => {
91
+ const session = await this.getOrCreate(owner, request, signal, validateOwnership);
92
+ const validatedOwner = await this.validatePooledOwnership(owner, request.sessionKey, signal, validateOwnership);
93
+ return this.#adapter.health?.(makeStatefulProviderSessionContext(this.#adapter.providerId, validatedOwner, request, signal), session.value);
94
+ });
95
+ }
96
+ async reconcileWrite(owner, request, ledgerEntry, signal, validateOwnership) {
97
+ if (!this.#adapter.reconcileWrite) {
98
+ throw new Error(`Stateful provider adapter "${this.#adapter.providerId}" does not support write reconciliation.`);
99
+ }
100
+ return this.schedule(owner.sessionKey, async () => {
101
+ const restoreCtx = makeStatefulProviderSessionContext(this.#adapter.providerId, owner, request, signal);
102
+ const sharedState = this.#adapter.restore
103
+ ? await this.#adapter.restore(restoreCtx)
104
+ : undefined;
105
+ const validatedOwner = validateOwnership ? await validateOwnership(owner, signal) : owner;
106
+ const ctx = makeStatefulProviderSessionContext(this.#adapter.providerId, validatedOwner, request, signal);
107
+ return this.#adapter.reconcileWrite?.(ctx, ledgerEntry, sharedState);
108
+ });
109
+ }
110
+ closeAll(reason) {
111
+ return this.#pool.closeAll(reason);
112
+ }
113
+ async getOrCreate(owner, request, signal, validateOwnership) {
114
+ return this.#pool.getOrCreate(owner.sessionKey, owner.generation, () => this.connect(owner, request, signal, validateOwnership), this.#clock(), managedSessionIdentity(owner, request));
115
+ }
116
+ async connect(owner, request, signal, validateOwnership) {
117
+ const ctx = makeStatefulProviderSessionContext(this.#adapter.providerId, owner, request, signal);
118
+ let session;
119
+ let connected = false;
120
+ try {
121
+ const sharedState = this.#adapter.restore ? await this.#adapter.restore(ctx) : undefined;
122
+ session = await this.#adapter.connect(ctx, sharedState);
123
+ connected = true;
124
+ const validatedOwner = validateOwnership ? await validateOwnership(owner, signal) : owner;
125
+ const validatedCtx = makeStatefulProviderSessionContext(this.#adapter.providerId, validatedOwner, request, signal);
126
+ this.refreshEventOwnerFence(validatedOwner, request.sessionKey);
127
+ if (!this.#adapter.subscribe || !this.#eventPublisher)
128
+ return session;
129
+ const identityKey = sessionIdentityKey(owner.sessionKey, owner.generation);
130
+ const disposer = await this.#adapter.subscribe(validatedCtx, session, (event) => {
131
+ const ownerFence = this.#eventOwnerFences.get(identityKey);
132
+ if (!ownerFence)
133
+ return;
134
+ this.#eventPublisher?.publish(event, { ownerFence });
135
+ });
136
+ if (typeof disposer !== "function") {
137
+ throw new Error(`Stateful provider adapter "${this.#adapter.providerId}" subscribe hook must return a disposer.`);
138
+ }
139
+ this.#eventDisposers.set(identityKey, disposer);
140
+ return session;
141
+ }
142
+ catch (error) {
143
+ this.#eventOwnerFences.delete(sessionIdentityKey(owner.sessionKey, owner.generation));
144
+ let establishmentError = error;
145
+ if (connected) {
146
+ try {
147
+ await this.#adapter.close(ctx, session, "session-establishment-failed");
148
+ }
149
+ catch (closeError) {
150
+ establishmentError = new AggregateError([error, closeError], "Stateful session establishment and cleanup both failed.");
151
+ }
152
+ }
153
+ throw markStatefulSessionEstablishmentFailure(establishmentError);
154
+ }
155
+ }
156
+ async validatePooledOwnership(owner, sessionKey, signal, validateOwnership) {
157
+ try {
158
+ const validatedOwner = validateOwnership ? await validateOwnership(owner, signal) : owner;
159
+ this.refreshEventOwnerFence(validatedOwner, sessionKey);
160
+ return validatedOwner;
161
+ }
162
+ catch (error) {
163
+ await this.#pool
164
+ .invalidate(owner.sessionKey, "ownership-validation-failed")
165
+ .catch(() => undefined);
166
+ throw markStatefulSessionEstablishmentFailure(error);
167
+ }
168
+ }
169
+ refreshEventOwnerFence(owner, sessionKey) {
170
+ this.#eventOwnerFences.set(sessionIdentityKey(owner.sessionKey, owner.generation), {
171
+ sessionKey,
172
+ generation: owner.generation,
173
+ ownerPodId: owner.ownerPodId,
174
+ ownerEndpoint: owner.ownerEndpoint,
175
+ });
176
+ }
177
+ async closeManagedSession(session, reason) {
178
+ const ctx = makeStatefulProviderCloseContext(this.#adapter.providerId, session);
179
+ const errors = [];
180
+ const disposerKey = sessionIdentityKey(session.sessionKey, session.generation);
181
+ const disposer = this.#eventDisposers.get(disposerKey);
182
+ this.#eventDisposers.delete(disposerKey);
183
+ this.#eventOwnerFences.delete(disposerKey);
184
+ if (disposer) {
185
+ try {
186
+ await disposer();
187
+ }
188
+ catch (error) {
189
+ errors.push(error);
190
+ }
191
+ }
192
+ if (this.#adapter.snapshot && this.#checkpointStore) {
193
+ try {
194
+ const state = await this.#adapter.snapshot(ctx, session.value);
195
+ if (state !== undefined)
196
+ await this.#checkpointStore(ctx, state);
197
+ }
198
+ catch (error) {
199
+ errors.push(error);
200
+ }
201
+ }
202
+ try {
203
+ await this.#adapter.close(ctx, session.value, reason);
204
+ }
205
+ catch (error) {
206
+ errors.push(error);
207
+ }
208
+ if (errors.length === 1)
209
+ throw errors[0];
210
+ if (errors.length > 1) {
211
+ throw new AggregateError(errors, "Stateful session cleanup failed in multiple hooks.");
212
+ }
213
+ }
214
+ observeDuration(request, owner, startedAt) {
215
+ observeStatefulSessionOperationDuration({
216
+ metricEmitter: this.#metricEmitter,
217
+ request,
218
+ owner,
219
+ durationMs: this.#clock().getTime() - startedAt,
220
+ });
221
+ }
222
+ async runLimited(sessionKey, maxInFlight, run) {
223
+ const limiter = this.#parallelLimiters.get(sessionKey) ?? { active: 0, waiting: [] };
224
+ this.#parallelLimiters.set(sessionKey, limiter);
225
+ if (limiter.active >= maxInFlight) {
226
+ await new Promise((resolve) => limiter.waiting.push(resolve));
227
+ }
228
+ limiter.active += 1;
229
+ try {
230
+ return await run();
231
+ }
232
+ finally {
233
+ limiter.active -= 1;
234
+ limiter.waiting.shift()?.();
235
+ if (limiter.active === 0 && limiter.waiting.length === 0) {
236
+ this.#parallelLimiters.delete(sessionKey);
237
+ }
238
+ }
239
+ }
240
+ schedule(sessionKey, run) {
241
+ const concurrency = this.#adapter.policy.concurrency;
242
+ if (concurrency.mode === "serialize")
243
+ return this.#pool.runExclusive(sessionKey, run);
244
+ if (concurrency.maxInFlight === undefined)
245
+ return run();
246
+ return this.runLimited(sessionKey, concurrency.maxInFlight, run);
247
+ }
248
+ }
249
+ function validateAdapterConfiguration(options) {
250
+ const adapter = options.adapter;
251
+ if (!adapter.policy?.concurrency || !adapter.policy.reconnect) {
252
+ throw new Error(`Stateful provider adapter "${adapter.providerId}" requires concurrency and reconnect policies.`);
253
+ }
254
+ const concurrency = adapter.policy.concurrency;
255
+ if (concurrency.mode !== "serialize" && concurrency.mode !== "parallel") {
256
+ throw new Error('Stateful concurrency policy mode must be "serialize" or "parallel".');
257
+ }
258
+ if (concurrency.mode === "serialize" && "maxInFlight" in concurrency) {
259
+ throw new Error("Stateful serialize concurrency must not declare maxInFlight.");
260
+ }
261
+ if (concurrency.mode === "parallel" &&
262
+ concurrency.maxInFlight !== undefined &&
263
+ (!Number.isInteger(concurrency.maxInFlight) || concurrency.maxInFlight <= 0)) {
264
+ throw new Error("Stateful parallel concurrency maxInFlight must be a positive integer.");
265
+ }
266
+ if (!["resume", "recreate", "unsupported"].includes(adapter.policy.reconnect)) {
267
+ throw new Error('Stateful reconnect policy must be "resume", "recreate", or "unsupported".');
268
+ }
269
+ if (Boolean(adapter.snapshot) !== Boolean(options.checkpointStore)) {
270
+ throw new Error(`Stateful provider adapter "${adapter.providerId}" snapshot and session-manager checkpointStore must be configured together.`);
271
+ }
272
+ if (Boolean(adapter.subscribe) !== Boolean(options.eventPublisher)) {
273
+ throw new Error(`Stateful provider adapter "${adapter.providerId}" subscribe and session-manager eventPublisher must be configured together.`);
274
+ }
275
+ }
276
+ function managedSessionIdentity(owner, request) {
277
+ return {
278
+ connectionId: request.connectionId,
279
+ serviceAccountId: request.serviceAccountId,
280
+ ownerPodId: owner.ownerPodId,
281
+ ownerEndpoint: owner.ownerEndpoint,
282
+ ownerStatus: owner.status,
283
+ };
284
+ }
285
+ function sessionIdentityKey(sessionKey, generation) {
286
+ return `${sessionKey}\u001f${generation}`;
287
+ }
@@ -0,0 +1,62 @@
1
+ export declare const STATEFUL_PROVIDER_METRIC_NAMES: readonly ["apifuse_stateful_provider_session_owner_acquire_total", "apifuse_stateful_provider_session_owner_renew_total", "apifuse_stateful_provider_session_owner_release_total", "apifuse_stateful_provider_session_owner_conflict_total", "apifuse_stateful_provider_session_owner_fencing_stale_total", "apifuse_stateful_provider_active_sessions", "apifuse_stateful_provider_lru_evictions_total", "apifuse_stateful_provider_session_invalidations_total", "apifuse_stateful_provider_session_operation_queue_depth", "apifuse_stateful_provider_session_operation_queue_wait_ms", "apifuse_stateful_provider_session_operation_duration_ms", "apifuse_stateful_provider_routing_forward_total", "apifuse_stateful_provider_routing_local_total", "apifuse_stateful_provider_routing_reacquire_total", "apifuse_stateful_provider_routing_deadline_expired_total", "apifuse_stateful_provider_event_append_total", "apifuse_stateful_provider_event_dedupe_total", "apifuse_stateful_provider_event_drop_total", "apifuse_stateful_provider_event_lag_ms", "apifuse_stateful_provider_webhook_enqueue_total", "apifuse_stateful_provider_webhook_fanout_recovered_total", "apifuse_stateful_provider_webhook_delivered_total", "apifuse_stateful_provider_webhook_retry_total", "apifuse_stateful_provider_webhook_dead_letter_total", "apifuse_stateful_provider_webhook_canceled_total", "apifuse_stateful_provider_webhook_replay_total", "apifuse_stateful_provider_webhook_latency_ms", "apifuse_stateful_provider_write_ledger_ambiguous_total", "apifuse_stateful_provider_write_ledger_reconciled_total", "apifuse_stateful_provider_write_ledger_failed_total"];
2
+ export type StatefulProviderMetricName = (typeof STATEFUL_PROVIDER_METRIC_NAMES)[number];
3
+ export declare const STATEFUL_PROVIDER_LOG_FIELDS: readonly ["requestId", "eventId", "deliveryId", "providerId", "connectionId", "serviceAccountId", "operationId", "sessionKeyHash", "ownerPodId", "generation", "leaseExpiresAt", "capacityClass", "queueDepth", "eventType", "subjectKind", "subjectId", "retryCount", "ledgerState", "healthStatus", "redactedErrorCode"];
4
+ export type StatefulProviderLogField = (typeof STATEFUL_PROVIDER_LOG_FIELDS)[number];
5
+ export declare const STATEFUL_PROVIDER_AUTOSCALING_SIGNALS: readonly ["active_sessions", "session_queue_depth", "session_queue_wait_ms", "reconnect_rate", "provider_event_lag_ms", "webhook_outbox_depth", "webhook_due_retry_depth", "memory_pressure", "file_descriptor_pressure", "socket_pressure"];
6
+ export type StatefulProviderAutoscalingSignal = (typeof STATEFUL_PROVIDER_AUTOSCALING_SIGNALS)[number];
7
+ export declare const STATEFUL_PROVIDER_HEALTH_DIMENSIONS: readonly ["registry_connectivity", "owner_lease_freshness", "pool_capacity", "upstream_auth_validity", "push_loop_lag", "event_append_lag", "webhook_backlog"];
8
+ export type StatefulProviderHealthDimension = (typeof STATEFUL_PROVIDER_HEALTH_DIMENSIONS)[number];
9
+ export declare const STATEFUL_PROVIDER_ROLLOUT_STATES: readonly ["disabled", "tenant_allowlist", "connection_allowlist", "shadow", "canary", "production", "rollback"];
10
+ export type StatefulProviderRolloutState = (typeof STATEFUL_PROVIDER_ROLLOUT_STATES)[number];
11
+ export interface StatefulProviderMetricLabelInput {
12
+ readonly requestId?: string;
13
+ readonly eventId?: string;
14
+ readonly deliveryId?: string;
15
+ readonly providerId?: string;
16
+ readonly connectionId?: string;
17
+ readonly serviceAccountId?: string;
18
+ readonly operationId?: string;
19
+ readonly sessionKey?: string;
20
+ readonly sessionKeyHash?: string;
21
+ readonly ownerPodId?: string;
22
+ readonly generation?: number | string;
23
+ readonly leaseExpiresAt?: string;
24
+ readonly capacityClass?: string;
25
+ readonly queueDepth?: number | string;
26
+ readonly eventType?: string;
27
+ readonly subjectKind?: string;
28
+ readonly subjectId?: string;
29
+ readonly retryCount?: number | string;
30
+ readonly ledgerState?: string;
31
+ readonly healthStatus?: string;
32
+ readonly redactedErrorCode?: string;
33
+ }
34
+ export type StatefulProviderMetricLabels = Partial<Record<StatefulProviderLogField, string>>;
35
+ export interface StatefulProviderMetricEmitter {
36
+ increment(name: StatefulProviderMetricName, labels?: StatefulProviderMetricLabelInput, value?: number): void;
37
+ gauge(name: StatefulProviderMetricName, labels: StatefulProviderMetricLabelInput, value: number): void;
38
+ observe(name: StatefulProviderMetricName, labels: StatefulProviderMetricLabelInput, value: number): void;
39
+ }
40
+ export type StatefulProviderRecordedMetric = {
41
+ readonly kind: "increment" | "gauge" | "observe";
42
+ readonly name: StatefulProviderMetricName;
43
+ readonly labels: StatefulProviderMetricLabels;
44
+ readonly value: number;
45
+ };
46
+ export declare const NOOP_STATEFUL_PROVIDER_METRIC_EMITTER: {
47
+ increment(): void;
48
+ gauge(): void;
49
+ observe(): void;
50
+ };
51
+ export declare class RecordingStatefulProviderMetricEmitter implements StatefulProviderMetricEmitter {
52
+ readonly metrics: StatefulProviderRecordedMetric[];
53
+ increment(name: StatefulProviderMetricName, labels?: StatefulProviderMetricLabelInput, value?: number): void;
54
+ gauge(name: StatefulProviderMetricName, labels: StatefulProviderMetricLabelInput, value: number): void;
55
+ observe(name: StatefulProviderMetricName, labels: StatefulProviderMetricLabelInput, value: number): void;
56
+ }
57
+ export declare function isStatefulProviderMetricName(value: unknown): value is StatefulProviderMetricName;
58
+ export declare function isStatefulProviderLogField(value: unknown): value is StatefulProviderLogField;
59
+ export declare function isStatefulProviderAutoscalingSignal(value: unknown): value is StatefulProviderAutoscalingSignal;
60
+ export declare function sanitizeSessionKeyForLog(sessionKey: string): string;
61
+ export declare function statefulProviderMetricLabels(input: StatefulProviderMetricLabelInput): StatefulProviderMetricLabels;
62
+ export declare function assertNoRawSessionKeyInLabels(labels: Record<string, string | number | boolean | null | undefined>, rawSessionKey: string): void;
@@ -0,0 +1,161 @@
1
+ import { createHash } from "node:crypto";
2
+ export const STATEFUL_PROVIDER_METRIC_NAMES = [
3
+ "apifuse_stateful_provider_session_owner_acquire_total",
4
+ "apifuse_stateful_provider_session_owner_renew_total",
5
+ "apifuse_stateful_provider_session_owner_release_total",
6
+ "apifuse_stateful_provider_session_owner_conflict_total",
7
+ "apifuse_stateful_provider_session_owner_fencing_stale_total",
8
+ "apifuse_stateful_provider_active_sessions",
9
+ "apifuse_stateful_provider_lru_evictions_total",
10
+ "apifuse_stateful_provider_session_invalidations_total",
11
+ "apifuse_stateful_provider_session_operation_queue_depth",
12
+ "apifuse_stateful_provider_session_operation_queue_wait_ms",
13
+ "apifuse_stateful_provider_session_operation_duration_ms",
14
+ "apifuse_stateful_provider_routing_forward_total",
15
+ "apifuse_stateful_provider_routing_local_total",
16
+ "apifuse_stateful_provider_routing_reacquire_total",
17
+ "apifuse_stateful_provider_routing_deadline_expired_total",
18
+ "apifuse_stateful_provider_event_append_total",
19
+ "apifuse_stateful_provider_event_dedupe_total",
20
+ "apifuse_stateful_provider_event_drop_total",
21
+ "apifuse_stateful_provider_event_lag_ms",
22
+ "apifuse_stateful_provider_webhook_enqueue_total",
23
+ "apifuse_stateful_provider_webhook_fanout_recovered_total",
24
+ "apifuse_stateful_provider_webhook_delivered_total",
25
+ "apifuse_stateful_provider_webhook_retry_total",
26
+ "apifuse_stateful_provider_webhook_dead_letter_total",
27
+ "apifuse_stateful_provider_webhook_canceled_total",
28
+ "apifuse_stateful_provider_webhook_replay_total",
29
+ "apifuse_stateful_provider_webhook_latency_ms",
30
+ "apifuse_stateful_provider_write_ledger_ambiguous_total",
31
+ "apifuse_stateful_provider_write_ledger_reconciled_total",
32
+ "apifuse_stateful_provider_write_ledger_failed_total",
33
+ ];
34
+ export const STATEFUL_PROVIDER_LOG_FIELDS = [
35
+ "requestId",
36
+ "eventId",
37
+ "deliveryId",
38
+ "providerId",
39
+ "connectionId",
40
+ "serviceAccountId",
41
+ "operationId",
42
+ "sessionKeyHash",
43
+ "ownerPodId",
44
+ "generation",
45
+ "leaseExpiresAt",
46
+ "capacityClass",
47
+ "queueDepth",
48
+ "eventType",
49
+ "subjectKind",
50
+ "subjectId",
51
+ "retryCount",
52
+ "ledgerState",
53
+ "healthStatus",
54
+ "redactedErrorCode",
55
+ ];
56
+ export const STATEFUL_PROVIDER_AUTOSCALING_SIGNALS = [
57
+ "active_sessions",
58
+ "session_queue_depth",
59
+ "session_queue_wait_ms",
60
+ "reconnect_rate",
61
+ "provider_event_lag_ms",
62
+ "webhook_outbox_depth",
63
+ "webhook_due_retry_depth",
64
+ "memory_pressure",
65
+ "file_descriptor_pressure",
66
+ "socket_pressure",
67
+ ];
68
+ export const STATEFUL_PROVIDER_HEALTH_DIMENSIONS = [
69
+ "registry_connectivity",
70
+ "owner_lease_freshness",
71
+ "pool_capacity",
72
+ "upstream_auth_validity",
73
+ "push_loop_lag",
74
+ "event_append_lag",
75
+ "webhook_backlog",
76
+ ];
77
+ export const STATEFUL_PROVIDER_ROLLOUT_STATES = [
78
+ "disabled",
79
+ "tenant_allowlist",
80
+ "connection_allowlist",
81
+ "shadow",
82
+ "canary",
83
+ "production",
84
+ "rollback",
85
+ ];
86
+ const METRIC_NAME_SET = new Set(STATEFUL_PROVIDER_METRIC_NAMES);
87
+ const LOG_FIELD_SET = new Set(STATEFUL_PROVIDER_LOG_FIELDS);
88
+ const AUTOSCALING_SIGNAL_SET = new Set(STATEFUL_PROVIDER_AUTOSCALING_SIGNALS);
89
+ export const NOOP_STATEFUL_PROVIDER_METRIC_EMITTER = {
90
+ increment() { },
91
+ gauge() { },
92
+ observe() { },
93
+ };
94
+ export class RecordingStatefulProviderMetricEmitter {
95
+ metrics = [];
96
+ increment(name, labels = {}, value = 1) {
97
+ this.metrics.push({
98
+ kind: "increment",
99
+ name,
100
+ labels: statefulProviderMetricLabels(labels),
101
+ value,
102
+ });
103
+ }
104
+ gauge(name, labels, value) {
105
+ this.metrics.push({
106
+ kind: "gauge",
107
+ name,
108
+ labels: statefulProviderMetricLabels(labels),
109
+ value,
110
+ });
111
+ }
112
+ observe(name, labels, value) {
113
+ this.metrics.push({
114
+ kind: "observe",
115
+ name,
116
+ labels: statefulProviderMetricLabels(labels),
117
+ value,
118
+ });
119
+ }
120
+ }
121
+ export function isStatefulProviderMetricName(value) {
122
+ return typeof value === "string" && METRIC_NAME_SET.has(value);
123
+ }
124
+ export function isStatefulProviderLogField(value) {
125
+ return typeof value === "string" && LOG_FIELD_SET.has(value);
126
+ }
127
+ export function isStatefulProviderAutoscalingSignal(value) {
128
+ return typeof value === "string" && AUTOSCALING_SIGNAL_SET.has(value);
129
+ }
130
+ export function sanitizeSessionKeyForLog(sessionKey) {
131
+ return `session_sha256:${createHash("sha256").update(sessionKey).digest("hex")}`;
132
+ }
133
+ export function statefulProviderMetricLabels(input) {
134
+ const labels = {};
135
+ for (const field of STATEFUL_PROVIDER_LOG_FIELDS) {
136
+ if (field === "sessionKeyHash")
137
+ continue;
138
+ const value = input[field];
139
+ if (value !== undefined) {
140
+ labels[field] = String(value);
141
+ }
142
+ }
143
+ const sessionKeyHash = input.sessionKeyHash ??
144
+ (input.sessionKey ? sanitizeSessionKeyForLog(input.sessionKey) : undefined);
145
+ if (sessionKeyHash) {
146
+ labels.sessionKeyHash = sessionKeyHash;
147
+ }
148
+ if (input.sessionKey) {
149
+ assertNoRawSessionKeyInLabels(labels, input.sessionKey);
150
+ }
151
+ return labels;
152
+ }
153
+ export function assertNoRawSessionKeyInLabels(labels, rawSessionKey) {
154
+ if (!rawSessionKey)
155
+ return;
156
+ for (const [key, value] of Object.entries(labels)) {
157
+ if (String(value ?? "").includes(rawSessionKey)) {
158
+ throw new Error(`Stateful provider metric label "${key}" contains a raw session key.`);
159
+ }
160
+ }
161
+ }
@@ -0,0 +1,41 @@
1
+ import type { ProviderServerStatefulForwardEnvelope } from "../server/serve.js";
2
+ import type { StatefulOperationRequest, StatefulOperationResult, StatefulOwnerForwarder } from "./stateful-provider-session-routing.js";
3
+ import type { SessionOwnerRecord, SessionOwnerRegistry } from "./stateful-provider-session-runtime.js";
4
+ export declare const STATEFUL_INTERNAL_OPERATIONS_ROUTE = "/__apifuse/stateful/operations";
5
+ export declare const STATEFUL_FORWARDING_SIGNATURE_HEADER = "x-apifuse-stateful-signature";
6
+ export declare const STATEFUL_FORWARDING_TIMESTAMP_HEADER = "x-apifuse-stateful-timestamp";
7
+ export declare const STATEFUL_FORWARDING_NONCE_HEADER = "x-apifuse-stateful-nonce";
8
+ export declare const STATEFUL_FORWARDING_SOURCE_POD_HEADER = "x-apifuse-stateful-source-pod";
9
+ export interface StatefulOwnerForwarderOptions {
10
+ readonly currentPodId: string;
11
+ readonly secret: string;
12
+ readonly fetch?: FetchTransport;
13
+ readonly clock?: () => Date;
14
+ }
15
+ type FetchTransport = (url: string | URL | Request, init?: RequestInit) => Promise<Response>;
16
+ /** Builds the standard fail-closed owner-currentness check for serve(). */
17
+ export declare function createStatefulOwnerFenceValidator(registry: SessionOwnerRegistry): (fence: Pick<ProviderServerStatefulForwardEnvelope, "sessionKey" | "ownerPodId" | "generation">, signal: AbortSignal) => Promise<boolean>;
18
+ export declare class StatefulOwnerForwardingError extends Error {
19
+ readonly code: string;
20
+ readonly status?: number;
21
+ constructor(input: {
22
+ readonly code: string;
23
+ readonly message: string;
24
+ readonly status?: number;
25
+ readonly cause?: unknown;
26
+ });
27
+ }
28
+ export declare class HttpStatefulOwnerForwarder implements StatefulOwnerForwarder {
29
+ #private;
30
+ constructor(options: StatefulOwnerForwarderOptions);
31
+ forward(owner: SessionOwnerRecord, request: StatefulOperationRequest, signal: AbortSignal): Promise<StatefulOperationResult>;
32
+ }
33
+ export declare function signStatefulForwardingBody(input: {
34
+ readonly secret: string;
35
+ readonly timestamp: string;
36
+ readonly rawBody: string;
37
+ readonly method: string;
38
+ readonly path: string;
39
+ readonly nonce: string;
40
+ }): string;
41
+ export {};