@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,247 @@
1
+ import { Buffer } from "node:buffer";
2
+ import type { ProviderCacheLookupMeta } from "../types.js";
3
+ import {
4
+ closedEnum,
5
+ type ClosedEnum,
6
+ type SpanIndex,
7
+ type TelemetryContributor,
8
+ } from "./request-telemetry.js";
9
+ import { createTelemetryObserver } from "./http-telemetry-guard.js";
10
+
11
+ export type CacheTelemetrySource = "memory" | "redis" | "loader";
12
+
13
+ export type CacheTelemetrySample = {
14
+ key: string;
15
+ hit: boolean;
16
+ stale: boolean;
17
+ ageMs?: number;
18
+ source: CacheTelemetrySource;
19
+ };
20
+
21
+ export type CacheTelemetryLogPayload = {
22
+ telemetryFailed?: true;
23
+ lookups: number;
24
+ hits: number;
25
+ stale: number;
26
+ misses: number;
27
+ writes: number;
28
+ loaderErrors: number;
29
+ writeErrors: number;
30
+ source: { memory: number; redis: number; loader: number };
31
+ redisFallbacks: number;
32
+ redisMode: ClosedEnum<"not_configured" | "configured" | "degraded">;
33
+ /** Successful Redis commands, including reads, writes, and deletes; memory-only work counts zero. */
34
+ redisRoundTrips: number;
35
+ ageMs?: { p50: number; max: number };
36
+ samples: CacheTelemetrySample[];
37
+ dropped: number;
38
+ };
39
+
40
+ export type CacheTelemetryHeaderPayload = Omit<
41
+ CacheTelemetryLogPayload,
42
+ "samples" | "ageMs" | "telemetryFailed"
43
+ > & {
44
+ ageP50?: number;
45
+ ageMax?: number;
46
+ };
47
+
48
+ export interface CacheTelemetrySink {
49
+ markTelemetryFailed?(): void;
50
+ setRedisConfigured?(configured: boolean): void;
51
+ recordLookup(meta: ProviderCacheLookupMeta): void;
52
+ recordWrite(): void;
53
+ recordLoaderError?(): void;
54
+ recordWriteError?(): void;
55
+ recordRedisFallback(): void;
56
+ recordRedisRoundTrip?(): void;
57
+ }
58
+
59
+ const cacheTelemetryBindings = new WeakMap<object, CacheTelemetrySink>();
60
+
61
+ /** Internal construction binding; keeps sink plumbing off ProviderCacheOptions. */
62
+ export function bindCacheTelemetry<T extends object>(
63
+ options: T,
64
+ sink: CacheTelemetrySink | undefined,
65
+ ): T {
66
+ if (sink) cacheTelemetryBindings.set(options, sink);
67
+ return options;
68
+ }
69
+
70
+ /** Internal lookup used only by the cache factory. */
71
+ export function cacheTelemetryFor(options: object): CacheTelemetrySink | undefined {
72
+ return cacheTelemetryBindings.get(options);
73
+ }
74
+
75
+ export function guardCacheTelemetry(sink: CacheTelemetrySink | undefined): CacheTelemetrySink {
76
+ const observe = createTelemetryObserver(sink);
77
+ return {
78
+ setRedisConfigured: (configured) => observe(() => sink?.setRedisConfigured?.(configured)),
79
+ recordLookup: (meta) => observe(() => sink?.recordLookup(meta)),
80
+ recordWrite: () => observe(() => sink?.recordWrite()),
81
+ recordLoaderError: () => observe(() => sink?.recordLoaderError?.()),
82
+ recordWriteError: () => observe(() => sink?.recordWriteError?.()),
83
+ recordRedisFallback: () => observe(() => sink?.recordRedisFallback()),
84
+ recordRedisRoundTrip: () => observe(() => sink?.recordRedisRoundTrip?.()),
85
+ };
86
+ }
87
+
88
+ const MAX_SAMPLES = 24;
89
+ const MAX_TEXT = 300;
90
+
91
+ function integer(value: number): number {
92
+ return Number.isFinite(value)
93
+ ? Math.min(Number.MAX_SAFE_INTEGER, Math.max(0, Math.floor(value)))
94
+ : Number.MAX_SAFE_INTEGER;
95
+ }
96
+
97
+ function add(a: number, b: number): number {
98
+ return Math.min(Number.MAX_SAFE_INTEGER, integer(a) + integer(b));
99
+ }
100
+
101
+ function boundedText(value: string, redact?: (text: string) => string): string {
102
+ let result: string;
103
+ try {
104
+ result = redact?.(value) ?? value;
105
+ } catch {
106
+ result = "[REDACTION_FAILED]";
107
+ }
108
+ const length = Math.min(result.length, MAX_TEXT);
109
+ const units = Buffer.alloc(length * 2);
110
+ for (let index = 0; index < length; index += 1)
111
+ units.writeUInt16LE(result.charCodeAt(index), index * 2);
112
+ return units.toString("utf16le");
113
+ }
114
+
115
+ export class CacheTelemetryCollector
116
+ implements
117
+ TelemetryContributor<CacheTelemetryLogPayload, CacheTelemetryHeaderPayload>,
118
+ CacheTelemetrySink
119
+ {
120
+ readonly key = "cache" as const;
121
+ readonly #redact?: (text: string) => string;
122
+ #telemetryFailed = false;
123
+ #lookups = 0;
124
+ #hits = 0;
125
+ #stale = 0;
126
+ #misses = 0;
127
+ #writes = 0;
128
+ #loaderErrors = 0;
129
+ #writeErrors = 0;
130
+ #source = { memory: 0, redis: 0, loader: 0 };
131
+ #redisFallbacks = 0;
132
+ #configured: "not_configured" | "configured" | "degraded";
133
+ #redisRoundTrips = 0;
134
+ #ages: number[] = [];
135
+ #maxAge = 0;
136
+ #samples: CacheTelemetrySample[] = [];
137
+ #dropped = 0;
138
+
139
+ constructor(options: { redact?: (text: string) => string } = {}) {
140
+ this.#redact = options.redact;
141
+ this.#configured = "not_configured";
142
+ }
143
+ setRedisConfigured(configured: boolean): void {
144
+ if (configured && this.#configured === "not_configured") this.#configured = "configured";
145
+ }
146
+ markTelemetryFailed(): void {
147
+ this.#telemetryFailed = true;
148
+ }
149
+
150
+ recordLookup(meta: ProviderCacheLookupMeta): void {
151
+ if (!["memory", "redis", "loader"].includes(meta.source)) {
152
+ this.#telemetryFailed = true;
153
+ return;
154
+ }
155
+ this.#lookups = add(this.#lookups, 1);
156
+ if (meta.hit) this.#hits = add(this.#hits, 1);
157
+ else this.#misses = add(this.#misses, 1);
158
+ if (meta.stale) this.#stale = add(this.#stale, 1);
159
+ this.#source[meta.source] = add(this.#source[meta.source], 1);
160
+ if (meta.source === "redis" && this.#configured === "not_configured")
161
+ this.#configured = "configured";
162
+ if (meta.ageMs !== undefined) {
163
+ const age = integer(meta.ageMs);
164
+ if (this.#ages.length < MAX_SAMPLES) this.#ages.push(age);
165
+ this.#maxAge = Math.max(this.#maxAge, age);
166
+ }
167
+ if (this.#samples.length < MAX_SAMPLES) {
168
+ this.#samples.push({
169
+ key: boundedText(meta.key, this.#redact),
170
+ hit: meta.hit,
171
+ stale: meta.stale,
172
+ ...(meta.ageMs === undefined ? {} : { ageMs: integer(meta.ageMs) }),
173
+ source: meta.source,
174
+ });
175
+ } else this.#dropped = add(this.#dropped, 1);
176
+ }
177
+
178
+ recordWrite(): void {
179
+ this.#writes = add(this.#writes, 1);
180
+ }
181
+ recordLoaderError(): void {
182
+ this.#loaderErrors = add(this.#loaderErrors, 1);
183
+ }
184
+ recordWriteError(): void {
185
+ this.#writeErrors = add(this.#writeErrors, 1);
186
+ }
187
+
188
+ recordRedisFallback(): void {
189
+ this.#redisFallbacks = add(this.#redisFallbacks, 1);
190
+ this.#configured = "degraded";
191
+ }
192
+
193
+ recordRedisRoundTrip(): void {
194
+ this.#redisRoundTrips = add(this.#redisRoundTrips, 1);
195
+ }
196
+
197
+ toLogPayload(_spans: SpanIndex): CacheTelemetryLogPayload | undefined {
198
+ if (
199
+ this.#lookups === 0 &&
200
+ this.#writes === 0 &&
201
+ this.#redisFallbacks === 0 &&
202
+ !this.#telemetryFailed
203
+ )
204
+ return undefined;
205
+ const sorted = [...this.#ages].sort((a, b) => a - b);
206
+ const p50 = sorted.length ? sorted[Math.floor((sorted.length - 1) / 2)]! : undefined;
207
+ return {
208
+ ...(this.#telemetryFailed ? { telemetryFailed: true as const } : {}),
209
+ lookups: this.#lookups,
210
+ hits: this.#hits,
211
+ stale: this.#stale,
212
+ misses: this.#misses,
213
+ writes: this.#writes,
214
+ loaderErrors: this.#loaderErrors,
215
+ writeErrors: this.#writeErrors,
216
+ source: { ...this.#source },
217
+ redisFallbacks: this.#redisFallbacks,
218
+ redisMode: closedEnum(this.#configured),
219
+ redisRoundTrips: this.#redisRoundTrips,
220
+ ...(p50 === undefined ? {} : { ageMs: { p50, max: this.#maxAge } }),
221
+ samples: this.#samples.map((sample) => ({ ...sample })),
222
+ dropped: this.#dropped,
223
+ };
224
+ }
225
+
226
+ toHeaderPayload(log: CacheTelemetryLogPayload): CacheTelemetryHeaderPayload {
227
+ return {
228
+ lookups: log.lookups,
229
+ hits: log.hits,
230
+ stale: log.stale,
231
+ misses: log.misses,
232
+ writes: log.writes,
233
+ loaderErrors: log.loaderErrors,
234
+ writeErrors: log.writeErrors,
235
+ source: {
236
+ memory: log.source.memory,
237
+ redis: log.source.redis,
238
+ loader: log.source.loader,
239
+ },
240
+ redisFallbacks: log.redisFallbacks,
241
+ redisMode: log.redisMode,
242
+ redisRoundTrips: log.redisRoundTrips,
243
+ ...(log.ageMs ? { ageP50: log.ageMs.p50, ageMax: log.ageMs.max } : {}),
244
+ dropped: log.dropped,
245
+ };
246
+ }
247
+ }
@@ -1,6 +1,8 @@
1
- import { createHash } from "node:crypto";
1
+ import { readDiagnosticEnv } from "./diagnostic-env.js";
2
+ import { createHash, createHmac } from "node:crypto";
2
3
 
3
4
  import { providerCacheRedisUrlFromEnv } from "../config/loader.js";
5
+ import { ProviderError } from "../errors.js";
4
6
  import type {
5
7
  ProviderCache,
6
8
  ProviderCacheGetOrSetOptions,
@@ -9,6 +11,7 @@ import type {
9
11
  ProviderCacheResponseMeta,
10
12
  ProviderCacheResult,
11
13
  } from "../types.js";
14
+ import { cacheTelemetryFor, guardCacheTelemetry } from "./cache-telemetry.js";
12
15
  import {
13
16
  createProviderRedisClient,
14
17
  ensureRedisReady,
@@ -43,9 +46,12 @@ export type ProviderCacheOptions = {
43
46
  now?: () => number;
44
47
  };
45
48
 
49
+ export const APIFUSE__CACHE__KEY_PEPPER_ENV = "APIFUSE__CACHE__KEY_PEPPER";
50
+
46
51
  const DEFAULT_PREFIX = "apifuse:provider-cache:v1";
47
52
  const DEFAULT_MEMORY_MAX_ENTRIES = 1_000;
48
53
  const DEFAULT_REDIS_TIMEOUT_MS = 150;
54
+ const SECRET_SCOPED_KEY_MARKER = "[secret-scoped";
49
55
  const SECRET_FIELD_NAMES = new Set([
50
56
  "authorization",
51
57
  "cookie",
@@ -61,6 +67,7 @@ const SECRET_FIELD_NAMES = new Set([
61
67
  ]);
62
68
 
63
69
  const sharedBackends = new Map<string, SharedCacheBackend>();
70
+ let warnedAboutUnpepperedSecretKeys = false;
64
71
 
65
72
  function backendKey(redisUrl: string | undefined): string {
66
73
  return redisUrl ?? "memory";
@@ -107,19 +114,172 @@ function shouldRedactField(name: string, extra: Set<string>): boolean {
107
114
  );
108
115
  }
109
116
 
110
- function normalizeKeyPart(value: unknown, extra: Set<string>): unknown {
117
+ type NormalizedKeyPart = {
118
+ value: unknown;
119
+ secretScoped: boolean;
120
+ };
121
+
122
+ function unsupportedSecretValue(path: string, reason: string): never {
123
+ throw new ProviderError(`Secret cache-key values must be JSON-safe; ${reason} at ${path}.`, {
124
+ code: "CACHE_KEY_SECRET_VALUE_UNSUPPORTED",
125
+ fix: "Convert the secret cache-key selector to JSON-safe primitives, arrays, or plain objects.",
126
+ });
127
+ }
128
+
129
+ function assertJsonSafeSecretValue(
130
+ value: unknown,
131
+ reportedPath: string,
132
+ ancestors = new Set<object>(),
133
+ ): void {
134
+ if (value === undefined) return;
135
+ if (value === null || typeof value === "string" || typeof value === "boolean") return;
136
+ if (typeof value === "number") {
137
+ if (!Number.isFinite(value))
138
+ unsupportedSecretValue(reportedPath, "non-finite numbers are unsupported");
139
+ if (Object.is(value, -0)) unsupportedSecretValue(reportedPath, "negative zero is unsupported");
140
+ return;
141
+ }
142
+ if (typeof value !== "object") {
143
+ unsupportedSecretValue(reportedPath, `${typeof value} values are unsupported`);
144
+ }
145
+ if (ancestors.has(value)) unsupportedSecretValue(reportedPath, "cyclic values are unsupported");
146
+
147
+ ancestors.add(value);
148
+ try {
149
+ if (Array.isArray(value)) {
150
+ if (Object.getOwnPropertySymbols(value).length > 0) {
151
+ unsupportedSecretValue(reportedPath, "symbol-keyed array properties are unsupported");
152
+ }
153
+ const expectedNames = new Set(["length"]);
154
+ for (let index = 0; index < value.length; index += 1) {
155
+ const key = String(index);
156
+ expectedNames.add(key);
157
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
158
+ if (!descriptor) unsupportedSecretValue(reportedPath, "sparse arrays are unsupported");
159
+ if (!descriptor.enumerable || !("value" in descriptor)) {
160
+ unsupportedSecretValue(reportedPath, "array accessors are unsupported");
161
+ }
162
+ assertJsonSafeSecretValue(descriptor.value, reportedPath, ancestors);
163
+ }
164
+ if (Object.getOwnPropertyNames(value).some((name) => !expectedNames.has(name))) {
165
+ unsupportedSecretValue(reportedPath, "custom array properties are unsupported");
166
+ }
167
+ return;
168
+ }
169
+
170
+ const prototype = Object.getPrototypeOf(value);
171
+ if (prototype !== Object.prototype && prototype !== null) {
172
+ unsupportedSecretValue(reportedPath, "non-plain objects are unsupported");
173
+ }
174
+ if (Object.getOwnPropertySymbols(value).length > 0) {
175
+ unsupportedSecretValue(reportedPath, "symbol-keyed properties are unsupported");
176
+ }
177
+ for (const key of Object.getOwnPropertyNames(value)) {
178
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
179
+ if (!descriptor?.enumerable || !("value" in descriptor)) {
180
+ unsupportedSecretValue(
181
+ reportedPath,
182
+ "non-enumerable properties and accessors are unsupported",
183
+ );
184
+ }
185
+ assertJsonSafeSecretValue(descriptor.value, reportedPath, ancestors);
186
+ }
187
+ } finally {
188
+ ancestors.delete(value);
189
+ }
190
+ }
191
+
192
+ function containsUndefined(value: unknown): boolean {
193
+ if (value === undefined) return true;
194
+ if (Array.isArray(value)) return value.some(containsUndefined);
195
+ if (isRecord(value)) return Object.values(value).some(containsUndefined);
196
+ return false;
197
+ }
198
+
199
+ function tagSecretValue(value: unknown): unknown {
200
+ if (value === undefined) return ["undefined"];
201
+ if (value === null) return ["null"];
202
+ if (typeof value === "string") return ["string", value];
203
+ if (typeof value === "number") return ["number", value];
204
+ if (typeof value === "boolean") return ["boolean", value];
205
+ if (Array.isArray(value)) return ["array", value.map(tagSecretValue)];
206
+ return [
207
+ "object",
208
+ Object.entries(value as Record<string, unknown>).map(([key, entry]) => [
209
+ key,
210
+ tagSecretValue(entry),
211
+ ]),
212
+ ];
213
+ }
214
+
215
+ function serializeSecretValue(value: unknown): string {
216
+ if (!containsUndefined(value)) return JSON.stringify([value]);
217
+ return `undefined-v1:${JSON.stringify(tagSecretValue(value))}`;
218
+ }
219
+
220
+ function warnAboutUnpepperedSecretKey(): void {
221
+ if (warnedAboutUnpepperedSecretKeys) return;
222
+ warnedAboutUnpepperedSecretKeys = true;
223
+ console.warn(
224
+ JSON.stringify({
225
+ level: "warn",
226
+ event: "provider_cache_secret_key_unpeppered",
227
+ message: `Secret-bearing cache keys are using unkeyed SHA-256 because ${APIFUSE__CACHE__KEY_PEPPER_ENV} is not configured.`,
228
+ }),
229
+ );
230
+ }
231
+
232
+ function normalizeKeyPart(
233
+ value: unknown,
234
+ extra: Set<string>,
235
+ pepper: string | undefined,
236
+ ): NormalizedKeyPart {
111
237
  if (Array.isArray(value)) {
112
- return value.map((entry) => normalizeKeyPart(entry, extra));
238
+ const entries = value.map((entry) => normalizeKeyPart(entry, extra, pepper));
239
+ return {
240
+ value: entries.map((entry) => entry.value),
241
+ secretScoped: entries.some((entry) => entry.secretScoped),
242
+ };
113
243
  }
114
244
  if (isRecord(value)) {
115
- const normalized: Record<string, unknown> = {};
245
+ const normalized: Record<string, unknown> = Object.create(null);
246
+ let secretScoped = false;
116
247
  for (const key of Object.keys(value).sort()) {
117
- if (shouldRedactField(key, extra)) continue;
118
- normalized[key] = normalizeKeyPart(value[key], extra);
248
+ const part = shouldRedactField(key, extra)
249
+ ? hashSecretValue(value[key], key, extra, pepper)
250
+ : normalizeKeyPart(value[key], extra, pepper);
251
+ normalized[key] = part.value;
252
+ secretScoped ||= part.secretScoped;
119
253
  }
120
- return normalized;
254
+ return { value: normalized, secretScoped };
121
255
  }
122
- return value;
256
+ return { value, secretScoped: false };
257
+ }
258
+
259
+ function hashSecretValue(
260
+ value: unknown,
261
+ fieldName: string,
262
+ extra: Set<string>,
263
+ pepper: string | undefined,
264
+ ): NormalizedKeyPart {
265
+ assertJsonSafeSecretValue(value, `${fieldName} (inside secret value)`);
266
+ const canonical = serializeSecretValue(normalizeKeyPart(value, extra, pepper).value);
267
+ if (pepper === undefined) {
268
+ warnAboutUnpepperedSecretKey();
269
+ const digest = createHash("sha256").update(canonical).digest("hex");
270
+ return { value: `sha256:${digest}`, secretScoped: true };
271
+ }
272
+ const digest = createHmac("sha256", pepper).update(canonical).digest("hex");
273
+ return { value: `hmac-sha256:${digest}`, secretScoped: true };
274
+ }
275
+
276
+ function metadataKeys(events: ProviderCacheLookupMeta[], secretScopedKeys: Set<string>): string[] {
277
+ let secretScopedIndex = 0;
278
+ return Array.from(new Set(events.map((event) => event.key))).map((key) => {
279
+ if (!secretScopedKeys.has(key)) return key;
280
+ secretScopedIndex += 1;
281
+ return `${SECRET_SCOPED_KEY_MARKER}#${secretScopedIndex}]`;
282
+ });
123
283
  }
124
284
 
125
285
  function stableHash(value: unknown): string {
@@ -198,13 +358,20 @@ async function withRedisFallback<T>(operation: () => Promise<T>): Promise<T | un
198
358
 
199
359
  export function createProviderCache(options: ProviderCacheOptions): ProviderCache {
200
360
  const redisUrl = options.redisUrl ?? providerCacheRedisUrlFromEnv();
361
+ const configuredPepper = readDiagnosticEnv(APIFUSE__CACHE__KEY_PEPPER_ENV);
362
+ const pepper = configuredPepper && configuredPepper.length > 0 ? configuredPepper : undefined;
201
363
  const backend = getSharedBackend(redisUrl);
202
364
  const memoryMaxEntries = Math.max(1, options.memoryMaxEntries ?? DEFAULT_MEMORY_MAX_ENTRIES);
203
365
  const now = options.now ?? Date.now;
204
366
  const events: ProviderCacheLookupMeta[] = [];
367
+ const telemetry = guardCacheTelemetry(cacheTelemetryFor(options));
368
+ telemetry.setRedisConfigured?.(!!redisUrl);
369
+ let redisUnavailable = false;
370
+ const secretScopedKeys = new Set<string>();
205
371
 
206
372
  function record(meta: ProviderCacheLookupMeta): void {
207
373
  events.push(meta);
374
+ telemetry?.recordLookup(meta);
208
375
  }
209
376
 
210
377
  function sweepMemory(currentTime: number): void {
@@ -248,13 +415,22 @@ export function createProviderCache(options: ProviderCacheOptions): ProviderCach
248
415
  } | null> {
249
416
  const redis = backend.redis;
250
417
  if (!redis || !(await ensureRedisReady(redis, DEFAULT_REDIS_TIMEOUT_MS))) {
418
+ if (redis) {
419
+ redisUnavailable = true;
420
+ telemetry?.recordRedisFallback();
421
+ }
251
422
  return null;
252
423
  }
253
424
 
254
425
  const raw = await withRedisFallback(async () => {
255
426
  return await redis.get(key);
256
427
  });
257
- if (typeof raw !== "string" && raw !== null) return null;
428
+ if (typeof raw !== "string" && raw !== null) {
429
+ redisUnavailable = true;
430
+ telemetry.recordRedisFallback();
431
+ return null;
432
+ }
433
+ telemetry?.recordRedisRoundTrip?.();
258
434
 
259
435
  const envelope = safeParseEnvelope(raw);
260
436
  if (!envelope) return null;
@@ -305,6 +481,7 @@ export function createProviderCache(options: ProviderCacheOptions): ProviderCach
305
481
  value: T,
306
482
  cacheOptions: ProviderCacheGetOrSetOptions,
307
483
  ): Promise<void> {
484
+ telemetry?.recordWrite();
308
485
  const currentTime = now();
309
486
  const freshTtlMs = jitteredTtlMs(cacheOptions.ttlMs, cacheOptions.jitterPct);
310
487
  const staleIfErrorMs = cacheOptions.staleIfErrorMs ?? 0;
@@ -319,9 +496,21 @@ export function createProviderCache(options: ProviderCacheOptions): ProviderCach
319
496
 
320
497
  const redis = backend.redis;
321
498
  if (!redis || !(await ensureRedisReady(redis, DEFAULT_REDIS_TIMEOUT_MS))) {
499
+ if (redis) {
500
+ redisUnavailable = true;
501
+ telemetry?.recordRedisFallback();
502
+ telemetry?.recordWriteError?.();
503
+ }
322
504
  return;
323
505
  }
324
- await withRedisFallback(() => redis.set(key, JSON.stringify(envelope), "PX", staleTtlMs));
506
+ const written = await withRedisFallback(() =>
507
+ redis.set(key, JSON.stringify(envelope), "PX", staleTtlMs),
508
+ );
509
+ if (written === undefined) {
510
+ redisUnavailable = true;
511
+ telemetry?.recordRedisFallback();
512
+ telemetry?.recordWriteError?.();
513
+ } else telemetry?.recordRedisRoundTrip?.();
325
514
  }
326
515
 
327
516
  async function loadAndStore<T>(
@@ -346,6 +535,13 @@ export function createProviderCache(options: ProviderCacheOptions): ProviderCach
346
535
  if (staleCandidate?.meta.stale) {
347
536
  return staleCandidate;
348
537
  }
538
+ telemetry?.recordLookup({
539
+ key,
540
+ hit: false,
541
+ stale: false,
542
+ source: "loader",
543
+ });
544
+ telemetry?.recordLoaderError?.();
349
545
  throw error;
350
546
  }
351
547
  }
@@ -353,25 +549,38 @@ export function createProviderCache(options: ProviderCacheOptions): ProviderCach
353
549
  return {
354
550
  key(namespace, parts, keyOptions?: ProviderCacheKeyOptions) {
355
551
  const extra = new Set((keyOptions?.redactFields ?? []).map((field) => field.toLowerCase()));
356
- const normalized = normalizeKeyPart(parts, extra);
357
- return `${DEFAULT_PREFIX}:${options.providerId}:${namespace}:${stableHash(normalized)}`;
552
+ const normalized = normalizeKeyPart(parts, extra, pepper);
553
+ const key = `${DEFAULT_PREFIX}:${options.providerId}:${namespace}:${stableHash(normalized.value)}`;
554
+ if (normalized.secretScoped) secretScopedKeys.add(key);
555
+ return key;
358
556
  },
359
557
 
360
558
  async get<T = unknown>(key: string): Promise<ProviderCacheResult<T> | null> {
361
559
  const result = await read<T>(key);
362
560
  if (result) record(result.meta);
561
+ else
562
+ telemetry.recordLookup({
563
+ key,
564
+ hit: false,
565
+ stale: false,
566
+ source: backend.redis && !redisUnavailable ? "redis" : "memory",
567
+ });
363
568
  return result;
364
569
  },
365
570
 
366
571
  set: write,
367
572
 
368
573
  async delete(key: string): Promise<void> {
574
+ telemetry?.recordWrite();
369
575
  backend.memory.delete(key);
370
576
  const redis = backend.redis;
371
577
  if (!redis || !(await ensureRedisReady(redis, DEFAULT_REDIS_TIMEOUT_MS))) {
578
+ if (redis) telemetry?.recordRedisFallback();
372
579
  return;
373
580
  }
374
- await withRedisFallback(() => redis.del(key));
581
+ const deleted = await withRedisFallback(() => redis.del(key));
582
+ if (deleted === undefined) telemetry?.recordRedisFallback();
583
+ else telemetry?.recordRedisRoundTrip?.();
375
584
  },
376
585
 
377
586
  async getOrSet<T = unknown>(
@@ -387,10 +596,22 @@ export function createProviderCache(options: ProviderCacheOptions): ProviderCach
387
596
 
388
597
  const existingInflight = backend.inflight.get(key);
389
598
  if (existingInflight) {
390
- const inflightResult = await existingInflight;
391
- const result = resultWithValue<T>(inflightResult.value, inflightResult.meta);
392
- record(result.meta);
393
- return result;
599
+ try {
600
+ const inflightResult = await existingInflight;
601
+ const result = resultWithValue<T>(inflightResult.value, inflightResult.meta);
602
+ record(result.meta);
603
+ return result;
604
+ } catch (error) {
605
+ const meta: ProviderCacheLookupMeta = {
606
+ key,
607
+ hit: false,
608
+ stale: false,
609
+ source: "loader",
610
+ };
611
+ telemetry.recordLookup(meta);
612
+ telemetry?.recordLoaderError?.();
613
+ throw error;
614
+ }
394
615
  }
395
616
 
396
617
  const promise: Promise<ProviderCacheResult<unknown>> = loadAndStore(
@@ -413,23 +634,35 @@ export function createProviderCache(options: ProviderCacheOptions): ProviderCach
413
634
  return {
414
635
  hit: events.some((event) => event.hit),
415
636
  stale: events.some((event) => event.stale),
416
- keys: Array.from(new Set(events.map((event) => event.key))),
637
+ keys: metadataKeys(events, secretScopedKeys),
417
638
  source: sourceSummary(events),
418
639
  };
419
640
  },
420
641
  };
421
642
  }
422
643
 
644
+ const bypassCaches = new WeakSet<ProviderCache>();
645
+
646
+ /** Internal cache capability, separate from hit/miss metadata. */
647
+ export function isProviderCacheBypassed(cache: ProviderCache): boolean {
648
+ return bypassCaches.has(cache);
649
+ }
650
+
423
651
  export function createBypassProviderCache(
424
652
  options: Pick<ProviderCacheOptions, "providerId">,
425
653
  ): ProviderCache {
654
+ const configuredPepper = readDiagnosticEnv(APIFUSE__CACHE__KEY_PEPPER_ENV);
655
+ const pepper = configuredPepper && configuredPepper.length > 0 ? configuredPepper : undefined;
426
656
  const events: ProviderCacheLookupMeta[] = [];
657
+ const secretScopedKeys = new Set<string>();
427
658
 
428
- return {
659
+ const cache: ProviderCache = {
429
660
  key(namespace, parts, keyOptions?: ProviderCacheKeyOptions) {
430
661
  const extra = new Set((keyOptions?.redactFields ?? []).map((field) => field.toLowerCase()));
431
- const normalized = normalizeKeyPart(parts, extra);
432
- return `${DEFAULT_PREFIX}:${options.providerId}:${namespace}:${stableHash(normalized)}`;
662
+ const normalized = normalizeKeyPart(parts, extra, pepper);
663
+ const key = `${DEFAULT_PREFIX}:${options.providerId}:${namespace}:${stableHash(normalized.value)}`;
664
+ if (normalized.secretScoped) secretScopedKeys.add(key);
665
+ return key;
433
666
  },
434
667
 
435
668
  async get<T = unknown>(_key: string): Promise<ProviderCacheResult<T> | null> {
@@ -464,11 +697,13 @@ export function createBypassProviderCache(
464
697
  return {
465
698
  hit: false,
466
699
  stale: false,
467
- keys: Array.from(new Set(events.map((event) => event.key))),
700
+ keys: metadataKeys(events, secretScopedKeys),
468
701
  source: sourceSummary(events),
469
702
  };
470
703
  },
471
704
  };
705
+ bypassCaches.add(cache);
706
+ return cache;
472
707
  }
473
708
 
474
709
  export function resetProviderCacheForTests(): void {
@@ -478,4 +713,5 @@ export function resetProviderCacheForTests(): void {
478
713
  backend.redis?.disconnect();
479
714
  }
480
715
  sharedBackends.clear();
716
+ warnedAboutUnpepperedSecretKeys = false;
481
717
  }