@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
package/src/handle.ts ADDED
@@ -0,0 +1,694 @@
1
+ /**
2
+ * LLM-friendly handles (ADR-0012): authoring API.
3
+ *
4
+ * A handle is a short string an LLM copies from one tool output into a later
5
+ * tool input. It is a lookup key to server state, never a carrier of encrypted
6
+ * payload. This module defines handle *kinds* (`defineCursor`, `defineDraft`),
7
+ * the schema helper `kind.field()`, the plain-value chooser `pick()`, and
8
+ * `HandleError`. The runtime (`ctx.handle`) lives in `runtime/handle.ts`.
9
+ */
10
+ import { type ZodString, type ZodType, z } from "zod";
11
+ import {
12
+ brandHandleError,
13
+ hasHandleErrorBrand,
14
+ ProviderError,
15
+ type ProviderErrorOptions,
16
+ } from "./errors.js";
17
+ import {
18
+ APIFUSE_HANDLE_META_KEY,
19
+ formatHandleIssuers,
20
+ handleFieldDescription,
21
+ handleHasDirectionalFieldNames,
22
+ HANDLE_KIND_NAME_PATTERN,
23
+ type HandleAccess,
24
+ type HandleFieldDirection,
25
+ type HandleFieldMeta,
26
+ type HandleFieldNames,
27
+ type HandleIssuedBy,
28
+ type HandleKindDeclaration,
29
+ type HandleKindType,
30
+ isHandleIssuedBy,
31
+ } from "./handle-meta.js";
32
+ import type { ProviderErrorCategory } from "./observability.js";
33
+ import {
34
+ BOUND_HANDLE_WORD_COUNT,
35
+ HIGH_PUBLIC_HANDLE_WORD_COUNT,
36
+ PUBLIC_HANDLE_WORD_COUNT,
37
+ } from "./runtime/handle-wordlist.js";
38
+ import type { ProviderStateDurationString } from "./types.js";
39
+
40
+ export type {
41
+ HandleAccess,
42
+ HandleFieldDirection,
43
+ HandleFieldMeta,
44
+ HandleFieldNames,
45
+ HandleIssuedBy,
46
+ HandleKindDeclaration,
47
+ HandleKindType,
48
+ };
49
+
50
+ /** Public kinds whose (max) ttl exceeds this are issued with five words (auto-high). */
51
+ const AUTO_HIGH_TTL_MS = 3_600_000;
52
+ const DEFAULT_BOUND_MAX_ENTRIES = 200;
53
+ const DEFAULT_CURSOR_MAX_VALUE_BYTES = 16_000;
54
+ const DEFAULT_DRAFT_MAX_VALUE_BYTES = 64_000;
55
+ const DEFAULT_RESULT_TTL: ProviderStateDurationString = "24h";
56
+
57
+ export type HandleStrength = "standard" | "high";
58
+
59
+ /** Words issued per handle: 2 for bound kinds, 4 for public, 5 for high-strength public. */
60
+ export type HandleWordCount = 2 | 4 | 5;
61
+
62
+ export interface HandleKindBase<TSchema extends ZodType = ZodType> extends HandleKindDeclaration {
63
+ /**
64
+ * Zod schema validated on `create`/`update`. Writes accept its *input* type
65
+ * (`InputOf`); stored records and callbacks carry its *output* type (`DataOf`).
66
+ */
67
+ readonly schema: TSchema;
68
+ /** Live-entry quota of the kind's namespace (per connection for bound kinds). */
69
+ readonly maxEntries: number;
70
+ /** Maximum JSON-encoded record size in bytes. */
71
+ readonly maxValueBytes: number;
72
+ /** Number of words the runtime issues for this kind. */
73
+ readonly wordCount: HandleWordCount;
74
+ /**
75
+ * Schema for the handle field, usable in output and input positions. Carries
76
+ * the `x-apifuse-handle` meta and an SDK-owned English description.
77
+ *
78
+ * One schema serves both directions even when the kind declares separate
79
+ * `input` / `output` property keys: the meta carries both names and lint
80
+ * checks the key against the side the field actually appears on.
81
+ */
82
+ field(): ZodString;
83
+ }
84
+
85
+ export interface CursorKind<TSchema extends ZodType = ZodType> extends HandleKindBase<TSchema> {
86
+ readonly type: "cursor";
87
+ readonly ttl: ProviderStateDurationString;
88
+ readonly ttlMs: number;
89
+ readonly strength: HandleStrength;
90
+ }
91
+
92
+ export interface DraftKind<
93
+ TSchema extends ZodType = ZodType,
94
+ TResultSchema extends ZodType | undefined = ZodType | undefined,
95
+ > extends HandleKindBase<TSchema> {
96
+ readonly type: "draft";
97
+ /** `"bound"` (default): connection-scoped, 2 words. `"public"`: provider-scoped, 4-5 words. */
98
+ readonly access: HandleAccess;
99
+ /** Public only; `"high"` forces 5 words. Always `"standard"` for bound drafts. */
100
+ readonly strength: HandleStrength;
101
+ readonly ttl: {
102
+ readonly idle: ProviderStateDurationString;
103
+ readonly max: ProviderStateDurationString;
104
+ };
105
+ readonly idleTtlMs: number;
106
+ readonly maxTtlMs: number;
107
+ readonly resultTtl: ProviderStateDurationString;
108
+ readonly resultTtlMs: number;
109
+ /** Optional schema describing the commit result; type-level only at runtime. */
110
+ readonly result: TResultSchema | undefined;
111
+ }
112
+
113
+ // `any` here is variance-only: a concrete `CursorKind<{ page: number }>` must be
114
+ // assignable to the union without callers spelling out the data type.
115
+ export type HandleKind = CursorKind<any> | DraftKind<any, any>;
116
+
117
+ /** Stored record data type (schema output); what `read`, `update`, and `commit` callbacks receive. */
118
+ export type DataOf<K extends HandleKind> = z.output<K["schema"]>;
119
+ /** What `create` and `update` accept (schema input); differs from `DataOf` when the schema transforms or defaults. */
120
+ export type InputOf<K extends HandleKind> = z.input<K["schema"]>;
121
+ export type ResultOf<K extends HandleKind> =
122
+ K extends DraftKind<any, infer R> ? (R extends ZodType ? z.output<R> : unknown) : never;
123
+
124
+ export type HandleStatus = "active" | "committing" | "committed";
125
+
126
+ export interface HandleRecord<K extends HandleKind> {
127
+ /** Canonical handle string (`<kind>_<word>-<word>...`). */
128
+ readonly handle: string;
129
+ readonly kind: string;
130
+ readonly status: HandleStatus;
131
+ readonly data: DataOf<K>;
132
+ readonly result?: ResultOf<K>;
133
+ readonly createdAt: string;
134
+ readonly expiresAt: string;
135
+ }
136
+
137
+ export interface HandleCommitResult<K extends HandleKind> {
138
+ readonly status: "committed" | "replayed";
139
+ readonly handle: string;
140
+ readonly result: ResultOf<K>;
141
+ }
142
+
143
+ export interface HandleContext {
144
+ /** Validates `data` with `kind.schema`, stores it, and returns the canonical handle. */
145
+ create<K extends HandleKind>(kind: K, data: InputOf<K>): Promise<string>;
146
+ /**
147
+ * Same as `create` but returns the full record (`handle`, `status`, `data`,
148
+ * `createdAt`, `expiresAt`) so a provider can expose `expires_at` without
149
+ * recomputing ttl math. `create` is the string-returning shortcut.
150
+ */
151
+ createRecord<K extends HandleKind>(kind: K, data: InputOf<K>): Promise<HandleRecord<K>>;
152
+ /** Tolerantly parses `handle`, loads the record; drafts get their idle TTL touched. */
153
+ read<K extends HandleKind>(kind: K, handle: string): Promise<HandleRecord<K>>;
154
+ /** CAS update of an active draft (3 retries) with sliding TTL. */
155
+ update<K extends DraftKind>(
156
+ kind: K,
157
+ handle: string,
158
+ updater: (data: DataOf<K>) => InputOf<K> | Promise<InputOf<K>>,
159
+ ): Promise<HandleRecord<K>>;
160
+ /** One-shot commit with result replay; see runtime docs for the state machine. */
161
+ commit<K extends DraftKind>(
162
+ kind: K,
163
+ handle: string,
164
+ work: (data: DataOf<K>) => Promise<ResultOf<K>>,
165
+ ): Promise<HandleCommitResult<K>>;
166
+ /** Deletes the record; idempotent. */
167
+ discard<K extends HandleKind>(kind: K, handle: string): Promise<void>;
168
+ }
169
+
170
+ export type HandleOperation = "create" | "read" | "update" | "commit" | "discard";
171
+
172
+ export type HandleTelemetryOutcome =
173
+ | "success"
174
+ | "not_found"
175
+ | "expired"
176
+ | "invalid"
177
+ | "kind_mismatch"
178
+ | "busy"
179
+ | "replayed"
180
+ | "error";
181
+
182
+ /** Allowlisted metadata only; handle values, data, and results are never included. */
183
+ export interface HandleTelemetryEvent {
184
+ readonly providerId: string;
185
+ readonly kind: string;
186
+ readonly type: HandleKindType;
187
+ readonly operation: HandleOperation;
188
+ readonly outcome: HandleTelemetryOutcome;
189
+ /** `"none"` or the sorted normalization classes joined by `+`. */
190
+ readonly normalization: string;
191
+ readonly words: number;
192
+ }
193
+
194
+ // ---------------------------------------------------------------------------
195
+ // Errors
196
+ // ---------------------------------------------------------------------------
197
+
198
+ export type HandleErrorCode =
199
+ | "HANDLE_INVALID"
200
+ | "HANDLE_NOT_FOUND"
201
+ | "HANDLE_EXPIRED"
202
+ | "HANDLE_KIND_MISMATCH"
203
+ | "HANDLE_BUSY"
204
+ | "HANDLE_COMMITTED"
205
+ | "HANDLE_CONNECTION_REQUIRED"
206
+ | "HANDLE_STORAGE_UNAVAILABLE"
207
+ | "HANDLE_TOO_LARGE"
208
+ | "HANDLE_INVALID_DATA"
209
+ | "PICK_NOT_OFFERED";
210
+
211
+ const HANDLE_ERROR_DEFAULTS: Record<
212
+ HandleErrorCode,
213
+ { readonly category: ProviderErrorCategory; readonly retryable: boolean }
214
+ > = {
215
+ HANDLE_INVALID: { category: "input_validation", retryable: false },
216
+ HANDLE_NOT_FOUND: { category: "input_validation", retryable: false },
217
+ HANDLE_EXPIRED: { category: "input_validation", retryable: false },
218
+ HANDLE_KIND_MISMATCH: { category: "input_validation", retryable: false },
219
+ HANDLE_BUSY: { category: "internal_error", retryable: true },
220
+ HANDLE_COMMITTED: { category: "input_validation", retryable: false },
221
+ HANDLE_CONNECTION_REQUIRED: { category: "internal_error", retryable: false },
222
+ HANDLE_STORAGE_UNAVAILABLE: { category: "internal_error", retryable: false },
223
+ HANDLE_TOO_LARGE: { category: "internal_error", retryable: false },
224
+ HANDLE_INVALID_DATA: { category: "internal_error", retryable: false },
225
+ PICK_NOT_OFFERED: { category: "input_validation", retryable: false },
226
+ };
227
+
228
+ export type HandleErrorOptions = Omit<ProviderErrorOptions, "code"> & {
229
+ /** Kind name the error relates to, when known. */
230
+ readonly kind?: string;
231
+ };
232
+
233
+ export class HandleError extends ProviderError {
234
+ readonly handleCode: HandleErrorCode;
235
+ readonly kind?: string;
236
+
237
+ constructor(code: HandleErrorCode, message: string, options: HandleErrorOptions = {}) {
238
+ const { kind, ...rest } = options;
239
+ const defaults = HANDLE_ERROR_DEFAULTS[code];
240
+ super(message, {
241
+ category: defaults.category,
242
+ retryable: defaults.retryable,
243
+ ...rest,
244
+ code,
245
+ });
246
+ this.name = "HandleError";
247
+ this.handleCode = code;
248
+ this.kind = kind;
249
+ brandHandleError(this);
250
+ }
251
+
252
+ override get code(): HandleErrorCode {
253
+ return this.handleCode;
254
+ }
255
+ }
256
+
257
+ /**
258
+ * Recognizes handle errors across duplicate SDK module copies (packaged CLI
259
+ * `src/*` runtime vs provider `dist/*` import), where `instanceof` splits.
260
+ */
261
+ export function isHandleError(value: unknown): value is HandleError {
262
+ return value instanceof HandleError || hasHandleErrorBrand(value);
263
+ }
264
+
265
+ /**
266
+ * Standard recovery sentence appended to every handle error message so the LLM
267
+ * knows the next action without provider-specific wording.
268
+ */
269
+ export function handleRecoverySentence(kind: {
270
+ readonly fieldName: string;
271
+ readonly outputFieldName?: string;
272
+ readonly issuedBy?: HandleIssuedBy;
273
+ }): string {
274
+ const issuers = formatHandleIssuers(kind.issuedBy);
275
+ // When the kind is issued under one key and accepted under another, naming
276
+ // only one of them tells the LLM to look for a field that is not there. Name
277
+ // the output key it reads and the input key it writes, in that order.
278
+ if (handleHasDirectionalFieldNames(kind)) {
279
+ const issued = kind.outputFieldName as string;
280
+ if (issuers) {
281
+ return `Call ${issuers} again and pass the new \`${issued}\` back as \`${kind.fieldName}\`, exactly as returned.`;
282
+ }
283
+ return `Request a new \`${issued}\` and pass it back as \`${kind.fieldName}\`, exactly as returned.`;
284
+ }
285
+ if (issuers) {
286
+ return `Call ${issuers} again and pass the new \`${kind.fieldName}\` exactly as returned.`;
287
+ }
288
+ return `Request a new \`${kind.fieldName}\` and pass it exactly as returned.`;
289
+ }
290
+
291
+ // ---------------------------------------------------------------------------
292
+ // Durations
293
+ // ---------------------------------------------------------------------------
294
+
295
+ const SHORT_DURATION_PATTERN = /^(\d+)(ms|s|m|h|d)$/;
296
+ const ISO_DURATION_PATTERN = /^PT(?:(\d+(?:\.\d+)?)H)?(?:(\d+(?:\.\d+)?)M)?(?:(\d+(?:\.\d+)?)S)?$/;
297
+
298
+ /** Parses a `ProviderStateDurationString` to milliseconds; throws on invalid or non-positive input. */
299
+ export function parseHandleDurationMs(value: ProviderStateDurationString, label: string): number {
300
+ const short = SHORT_DURATION_PATTERN.exec(value);
301
+ let ms: number | undefined;
302
+ if (short) {
303
+ const amount = Number(short[1]);
304
+ const unit = short[2];
305
+ const multiplier =
306
+ unit === "ms"
307
+ ? 1
308
+ : unit === "s"
309
+ ? 1_000
310
+ : unit === "m"
311
+ ? 60_000
312
+ : unit === "h"
313
+ ? 3_600_000
314
+ : 86_400_000;
315
+ ms = amount * multiplier;
316
+ } else {
317
+ const iso = ISO_DURATION_PATTERN.exec(value);
318
+ if (iso && (iso[1] !== undefined || iso[2] !== undefined || iso[3] !== undefined)) {
319
+ ms =
320
+ Number(iso[1] ?? 0) * 3_600_000 +
321
+ Number(iso[2] ?? 0) * 60_000 +
322
+ Number(iso[3] ?? 0) * 1_000;
323
+ }
324
+ }
325
+ if (ms === undefined || !Number.isFinite(ms) || ms <= 0) {
326
+ throw new Error(
327
+ `Handle kind ${label} must be a positive duration such as "10m", "2h", or "PT30M" (received ${JSON.stringify(value)}).`,
328
+ );
329
+ }
330
+ return Math.floor(ms);
331
+ }
332
+
333
+ // ---------------------------------------------------------------------------
334
+ // Kind definitions
335
+ // ---------------------------------------------------------------------------
336
+
337
+ export interface DefineCursorOptions<TSchema extends ZodType> {
338
+ /** Kind name, `/^[a-z]{2,12}$/`; becomes the handle prefix. */
339
+ readonly name: string;
340
+ /**
341
+ * Schema property key carrying the handle. Default `${name}_token`.
342
+ *
343
+ * Pass `{ input, output }` when the caller-facing contract names the same
344
+ * handle differently in each direction — the canon's `{ input: "cursor",
345
+ * output: "next_cursor" }`. Both keys must be given; the handle's identity
346
+ * stays the kind, so a value issued under `output` is still only valid when
347
+ * sent back under `input`.
348
+ */
349
+ readonly fieldName?: string | HandleFieldNames;
350
+ readonly schema: TSchema;
351
+ readonly ttl: ProviderStateDurationString;
352
+ /** `"bound"` (default): connection-scoped, 2 words. `"public"`: provider-scoped, 4-5 words. */
353
+ readonly access?: HandleAccess;
354
+ /** Required when public. Bound default 200 per connection. */
355
+ readonly maxEntries?: number;
356
+ /** Default 16,000. */
357
+ readonly maxValueBytes?: number;
358
+ /** Public only; `"high"` forces 5 words. Auto-high when ttl > 1h. */
359
+ readonly strength?: HandleStrength;
360
+ /** Operation key(s) that issue this handle; used in error text and lint. */
361
+ readonly issuedBy?: HandleIssuedBy;
362
+ }
363
+
364
+ export interface DefineDraftOptions<
365
+ TSchema extends ZodType,
366
+ TResultSchema extends ZodType | undefined,
367
+ > {
368
+ readonly name: string;
369
+ /**
370
+ * Schema property key carrying the handle. Default `${name}_token`. Accepts
371
+ * `{ input, output }` for a contract that names the handle differently in
372
+ * each direction; see {@link DefineCursorOptions.fieldName}.
373
+ */
374
+ readonly fieldName?: string | HandleFieldNames;
375
+ readonly schema: TSchema;
376
+ /** Optional schema of the commit result (type-level). */
377
+ readonly result?: TResultSchema;
378
+ readonly ttl: {
379
+ readonly idle: ProviderStateDurationString;
380
+ readonly max: ProviderStateDurationString;
381
+ };
382
+ /** How long a committed record stays for replay. Default "24h". */
383
+ readonly resultTtl?: ProviderStateDurationString;
384
+ /**
385
+ * `"bound"` (default): connection-scoped, 2 words. `"public"`: provider-scoped
386
+ * draft for connectionless providers (`auth: none`), 4-5 words, `maxEntries`
387
+ * required; every lookup failure collapses to `HANDLE_INVALID`.
388
+ */
389
+ readonly access?: HandleAccess;
390
+ /** Required when public. Bound default 200 per connection. */
391
+ readonly maxEntries?: number;
392
+ /** Default 64,000. */
393
+ readonly maxValueBytes?: number;
394
+ /** Public only; `"high"` forces 5 words. Auto-high when ttl.max > 1h. */
395
+ readonly strength?: HandleStrength;
396
+ /** Operation key(s) that issue this handle; used in error text and lint. */
397
+ readonly issuedBy?: HandleIssuedBy;
398
+ }
399
+
400
+ function assertKindName(name: unknown, define: string): asserts name is string {
401
+ if (typeof name !== "string" || !HANDLE_KIND_NAME_PATTERN.test(name)) {
402
+ throw new Error(
403
+ `${define}: kind name must match ${HANDLE_KIND_NAME_PATTERN} (2-12 lowercase letters, no digits or separators) so it never fuses with the word body; received ${JSON.stringify(name)}.`,
404
+ );
405
+ }
406
+ }
407
+
408
+ function assertFieldName(
409
+ fieldName: unknown,
410
+ define: string,
411
+ label: string,
412
+ ): asserts fieldName is string {
413
+ if (typeof fieldName !== "string" || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(fieldName)) {
414
+ throw new Error(
415
+ `${define}: ${label} must be a plain identifier usable as a schema property key; received ${JSON.stringify(fieldName)}.`,
416
+ );
417
+ }
418
+ }
419
+
420
+ /**
421
+ * Resolves the `fieldName` option to the input key and, when the two differ,
422
+ * the output key.
423
+ *
424
+ * The string form names one key for both directions and is unchanged. The
425
+ * object form requires BOTH keys: a half-declaration would leave one side
426
+ * silently defaulting to `${name}_token`, which is the kind of mismatch this
427
+ * option exists to make explicit. `outputFieldName` is left undefined when the
428
+ * two keys are equal so a one-name kind emits exactly the meta it always did.
429
+ */
430
+ function resolveFieldNames(
431
+ value: string | HandleFieldNames | undefined,
432
+ define: string,
433
+ name: string,
434
+ ): { fieldName: string; outputFieldName?: string } {
435
+ if (value === undefined) return { fieldName: `${name}_token` };
436
+ if (typeof value === "string") {
437
+ assertFieldName(value, define, "fieldName");
438
+ return { fieldName: value };
439
+ }
440
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
441
+ throw new Error(
442
+ `${define}: "${name}" fieldName must be a property key or { input, output }; received ${JSON.stringify(value)}.`,
443
+ );
444
+ }
445
+ const record = value as unknown as Record<string, unknown>;
446
+ const extra = Object.keys(record).filter((key) => key !== "input" && key !== "output");
447
+ if (extra.length > 0) {
448
+ throw new Error(
449
+ `${define}: "${name}" fieldName accepts only "input" and "output"; received extra ${extra.map((key) => JSON.stringify(key)).join(", ")}.`,
450
+ );
451
+ }
452
+ if (record.input === undefined || record.output === undefined) {
453
+ throw new Error(
454
+ `${define}: "${name}" fieldName must declare both "input" and "output" when the two directions differ; declaring one would leave the other defaulting to "${name}_token".`,
455
+ );
456
+ }
457
+ assertFieldName(record.input, define, "fieldName.input");
458
+ assertFieldName(record.output, define, "fieldName.output");
459
+ if (record.input === record.output) return { fieldName: record.input };
460
+ return { fieldName: record.input, outputFieldName: record.output };
461
+ }
462
+
463
+ function assertPositiveInteger(value: number, label: string, define: string): void {
464
+ if (!Number.isInteger(value) || value <= 0) {
465
+ throw new Error(`${define}: ${label} must be a positive integer; received ${String(value)}.`);
466
+ }
467
+ }
468
+
469
+ function assertAccess(value: unknown, define: string): asserts value is HandleAccess {
470
+ if (value !== "bound" && value !== "public") {
471
+ throw new Error(`${define}: access must be "bound" or "public"; received ${String(value)}.`);
472
+ }
473
+ }
474
+
475
+ function assertStrength(value: unknown, define: string): asserts value is HandleStrength {
476
+ if (value !== "standard" && value !== "high") {
477
+ throw new Error(`${define}: strength must be "standard" or "high"; received ${String(value)}.`);
478
+ }
479
+ }
480
+
481
+ /** Validates `issuedBy` and returns a frozen copy for lists; `undefined` stays undefined. */
482
+ function normalizeIssuedBy(
483
+ value: unknown,
484
+ define: string,
485
+ name: string,
486
+ ): HandleIssuedBy | undefined {
487
+ if (value === undefined) return undefined;
488
+ if (!isHandleIssuedBy(value) || (typeof value === "string" ? value.length === 0 : false)) {
489
+ throw new Error(
490
+ `${define}: "${name}" issuedBy must be an operation key or a non-empty list of operation keys; received ${JSON.stringify(value)}.`,
491
+ );
492
+ }
493
+ if (typeof value === "string") return value;
494
+ if (value.some((operation) => operation.length === 0)) {
495
+ throw new Error(`${define}: "${name}" issuedBy must not contain empty operation keys.`);
496
+ }
497
+ return Object.freeze([...value]);
498
+ }
499
+
500
+ /** Word count for a kind: 2 bound; public 4, or 5 when high strength or the lifetime exceeds 1h. */
501
+ function wordCountFor(
502
+ access: HandleAccess,
503
+ strength: HandleStrength,
504
+ lifetimeMs: number,
505
+ ): HandleWordCount {
506
+ if (access === "bound") return BOUND_HANDLE_WORD_COUNT;
507
+ return strength === "high" || lifetimeMs > AUTO_HIGH_TTL_MS
508
+ ? HIGH_PUBLIC_HANDLE_WORD_COUNT
509
+ : PUBLIC_HANDLE_WORD_COUNT;
510
+ }
511
+
512
+ function createHandleField(meta: HandleFieldMeta): ZodString {
513
+ const described = z.string().min(1).describe(handleFieldDescription(meta));
514
+ // zod v4 `.meta()` replaces the registry entry, so carry the description over.
515
+ const existing = described.meta() ?? {};
516
+ return described.meta({ ...existing, [APIFUSE_HANDLE_META_KEY]: meta });
517
+ }
518
+
519
+ /** Defines an immutable cursor kind (pagination, offered option lists). */
520
+ export function defineCursor<TSchema extends ZodType>(
521
+ options: DefineCursorOptions<TSchema>,
522
+ ): CursorKind<TSchema> {
523
+ const define = "defineCursor";
524
+ assertKindName(options.name, define);
525
+ const { fieldName, outputFieldName } = resolveFieldNames(options.fieldName, define, options.name);
526
+ const access: unknown = options.access ?? "bound";
527
+ assertAccess(access, define);
528
+ const ttlMs = parseHandleDurationMs(options.ttl, `"${options.name}" ttl`);
529
+ const strength: unknown = options.strength ?? "standard";
530
+ assertStrength(strength, define);
531
+ const issuedBy = normalizeIssuedBy(options.issuedBy, define, options.name);
532
+ if (access === "public" && options.maxEntries === undefined) {
533
+ throw new Error(
534
+ `${define}: public cursor "${options.name}" must declare maxEntries (provider-wide live-entry quota).`,
535
+ );
536
+ }
537
+ const maxEntries = options.maxEntries ?? DEFAULT_BOUND_MAX_ENTRIES;
538
+ assertPositiveInteger(maxEntries, "maxEntries", define);
539
+ const maxValueBytes = options.maxValueBytes ?? DEFAULT_CURSOR_MAX_VALUE_BYTES;
540
+ assertPositiveInteger(maxValueBytes, "maxValueBytes", define);
541
+ const wordCount = wordCountFor(access, strength, ttlMs);
542
+ const meta: HandleFieldMeta = {
543
+ kind: options.name,
544
+ type: "cursor",
545
+ fieldName,
546
+ ...(outputFieldName ? { outputFieldName } : {}),
547
+ ...(issuedBy ? { issuedBy } : {}),
548
+ };
549
+ return Object.freeze({
550
+ name: options.name,
551
+ type: "cursor",
552
+ fieldName,
553
+ outputFieldName,
554
+ access,
555
+ issuedBy,
556
+ schema: options.schema,
557
+ ttl: options.ttl,
558
+ ttlMs,
559
+ strength,
560
+ maxEntries,
561
+ maxValueBytes,
562
+ wordCount,
563
+ field: () => createHandleField(meta),
564
+ });
565
+ }
566
+
567
+ /**
568
+ * Defines a mutable draft kind (multi-turn forms with one-shot commit). Bound
569
+ * by default; `access: "public"` opts a connectionless provider into a
570
+ * provider-scoped draft under the public guessing analysis (ADR-0012 D3).
571
+ */
572
+ export function defineDraft<
573
+ TSchema extends ZodType,
574
+ TResultSchema extends ZodType | undefined = undefined,
575
+ >(options: DefineDraftOptions<TSchema, TResultSchema>): DraftKind<TSchema, TResultSchema> {
576
+ const define = "defineDraft";
577
+ assertKindName(options.name, define);
578
+ const { fieldName, outputFieldName } = resolveFieldNames(options.fieldName, define, options.name);
579
+ if (!options.ttl || typeof options.ttl !== "object") {
580
+ throw new Error(`${define}: draft "${options.name}" ttl must be { idle, max }.`);
581
+ }
582
+ const idleTtlMs = parseHandleDurationMs(options.ttl.idle, `"${options.name}" ttl.idle`);
583
+ const maxTtlMs = parseHandleDurationMs(options.ttl.max, `"${options.name}" ttl.max`);
584
+ if (idleTtlMs > maxTtlMs) {
585
+ throw new Error(
586
+ `${define}: draft "${options.name}" ttl.idle (${idleTtlMs}ms) must not exceed ttl.max (${maxTtlMs}ms).`,
587
+ );
588
+ }
589
+ const resultTtl = options.resultTtl ?? DEFAULT_RESULT_TTL;
590
+ const resultTtlMs = parseHandleDurationMs(resultTtl, `"${options.name}" resultTtl`);
591
+ const access: unknown = options.access ?? "bound";
592
+ assertAccess(access, define);
593
+ const strength: unknown = options.strength ?? "standard";
594
+ assertStrength(strength, define);
595
+ if (access === "bound" && strength !== "standard") {
596
+ throw new Error(
597
+ `${define}: draft "${options.name}" strength applies to public drafts only; bound drafts are always two words.`,
598
+ );
599
+ }
600
+ const issuedBy = normalizeIssuedBy(options.issuedBy, define, options.name);
601
+ if (access === "public" && options.maxEntries === undefined) {
602
+ throw new Error(
603
+ `${define}: public draft "${options.name}" must declare maxEntries (provider-wide live-entry quota).`,
604
+ );
605
+ }
606
+ const maxEntries = options.maxEntries ?? DEFAULT_BOUND_MAX_ENTRIES;
607
+ assertPositiveInteger(maxEntries, "maxEntries", define);
608
+ const maxValueBytes = options.maxValueBytes ?? DEFAULT_DRAFT_MAX_VALUE_BYTES;
609
+ assertPositiveInteger(maxValueBytes, "maxValueBytes", define);
610
+ // A public draft's guessable lifetime is its hard `max` ttl (idle only shortens it).
611
+ const wordCount = wordCountFor(access, strength, maxTtlMs);
612
+ const meta: HandleFieldMeta = {
613
+ kind: options.name,
614
+ type: "draft",
615
+ fieldName,
616
+ ...(outputFieldName ? { outputFieldName } : {}),
617
+ ...(issuedBy ? { issuedBy } : {}),
618
+ };
619
+ return Object.freeze({
620
+ name: options.name,
621
+ type: "draft",
622
+ fieldName,
623
+ outputFieldName,
624
+ access,
625
+ strength,
626
+ issuedBy,
627
+ schema: options.schema,
628
+ result: options.result,
629
+ ttl: options.ttl,
630
+ idleTtlMs,
631
+ maxTtlMs,
632
+ resultTtl,
633
+ resultTtlMs,
634
+ maxEntries,
635
+ maxValueBytes,
636
+ wordCount,
637
+ field: () => createHandleField(meta),
638
+ });
639
+ }
640
+
641
+ export function isDraftKind(kind: HandleKind): kind is DraftKind<any, any> {
642
+ return kind.type === "draft";
643
+ }
644
+
645
+ export function isCursorKind(kind: HandleKind): kind is CursorKind<any> {
646
+ return kind.type === "cursor";
647
+ }
648
+
649
+ // ---------------------------------------------------------------------------
650
+ // pick
651
+ // ---------------------------------------------------------------------------
652
+
653
+ export interface PickOptions<T> {
654
+ /** Input field name, used in the error message. */
655
+ readonly field: string;
656
+ /** Item property compared against `value`. Default = `field`. */
657
+ readonly by?: keyof T & string;
658
+ /** Operation(s) that listed the items; used in the error message when known. */
659
+ readonly issuedBy?: HandleIssuedBy;
660
+ }
661
+
662
+ /**
663
+ * Chooses one offered item by a plain value the LLM copied from the offer.
664
+ * Exact match first, then a unique case-insensitive trimmed match; otherwise
665
+ * `PICK_NOT_OFFERED` with the allowed values so the LLM can self-correct. The
666
+ * server holds the offer, so a fabricated value fails here instead of reaching
667
+ * upstream. This is the "one handle per offer + plain picks" half of ADR-0012.
668
+ */
669
+ export function pick<T extends Record<string, unknown>>(
670
+ items: readonly T[],
671
+ value: string,
672
+ options: PickOptions<T>,
673
+ ): T {
674
+ const by = options.by ?? options.field;
675
+ const keyOf = (item: T): string => {
676
+ const raw = item[by];
677
+ return typeof raw === "string" ? raw : String(raw);
678
+ };
679
+ const exact = items.find((item) => keyOf(item) === value);
680
+ if (exact) return exact;
681
+ const folded = value.trim().toLowerCase();
682
+ const loose = items.filter((item) => keyOf(item).trim().toLowerCase() === folded);
683
+ if (loose.length === 1) return loose[0]!;
684
+ const allowed = items.map(keyOf);
685
+ const issuers = formatHandleIssuers(options.issuedBy);
686
+ const listed = issuers
687
+ ? ` Use the values exactly as listed by ${issuers}.`
688
+ : " Use the values exactly as listed.";
689
+ throw new HandleError(
690
+ "PICK_NOT_OFFERED",
691
+ `\`${options.field}\` must be one of: ${allowed.join(", ")}.${listed}`,
692
+ { details: { field: options.field, allowed } },
693
+ );
694
+ }