@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,364 @@
1
+ import { z } from "zod";
2
+
3
+ import type { ProviderDeploymentOverrides } from "../types.js";
4
+
5
+ /**
6
+ * Deployment-intent helpers shared by `apifuse check` and
7
+ * `apifuse migrate-deployment`.
8
+ *
9
+ * Deployment intent has exactly one authored home: the optional `deployment`
10
+ * key on `defineProvider()`. The APIFuse registry builder is the only reader;
11
+ * it resolves omitted fields from a runtime profile and rejects anything it
12
+ * cannot resolve. This module mirrors that profile table so the CLI can
13
+ * (a) subtract profile defaults when hoisting a legacy `deploy.ts` into the
14
+ * key and (b) warn when a declared key restates a default. The registry
15
+ * stays canonical — keep the constants below identical to
16
+ * `resolveProviderDeploymentConfig` in `@apifuse/provider-registry`.
17
+ */
18
+
19
+ export type DeploymentRuntime = "shared" | "dedicated" | "browser";
20
+ export type DeploymentLanguage = "typescript" | "python";
21
+
22
+ export interface DeploymentResources {
23
+ cpu: string;
24
+ memory: string;
25
+ }
26
+
27
+ export interface DeploymentHpa {
28
+ enabled: boolean;
29
+ minReplicas?: number;
30
+ maxReplicas?: number;
31
+ targetCPUUtilizationPercentage?: number;
32
+ }
33
+
34
+ /** Fully resolved deployment view: what the platform materializes for a provider. */
35
+ export interface ResolvedDeploymentIntent {
36
+ runtime: DeploymentRuntime;
37
+ language: DeploymentLanguage;
38
+ replicas: number;
39
+ hpa: DeploymentHpa;
40
+ resources: DeploymentResources;
41
+ cache?: { redis?: { enabled: boolean; url?: string } };
42
+ network?: { additionalTcpPorts: number[] };
43
+ buildContext: string;
44
+ }
45
+
46
+ /**
47
+ * Runtime-profile defaults. `dedicated` carries no resource profile and
48
+ * therefore always needs explicit `resources`.
49
+ */
50
+ export const DEPLOYMENT_PROFILE_DEFAULTS = Object.freeze({
51
+ runtime: "shared" as DeploymentRuntime,
52
+ language: "typescript" as DeploymentLanguage,
53
+ replicas: 1,
54
+ hpa: Object.freeze({
55
+ enabled: true,
56
+ minReplicas: 1,
57
+ maxReplicas: 1,
58
+ targetCPUUtilizationPercentage: 70,
59
+ }) as Readonly<DeploymentHpa>,
60
+ buildContext: ".",
61
+ resources: Object.freeze({
62
+ shared: Object.freeze({ cpu: "25m", memory: "128Mi" }),
63
+ browser: Object.freeze({ cpu: "200m", memory: "256Mi" }),
64
+ dedicated: undefined,
65
+ }) as Readonly<Record<DeploymentRuntime, Readonly<DeploymentResources> | undefined>>,
66
+ });
67
+
68
+ const BUILD_CONTEXT_CONSTRAINT =
69
+ 'only "." is accepted; external provider images always build from the materialized checkout root';
70
+
71
+ const hpaSchema = z
72
+ .object({
73
+ enabled: z.boolean(),
74
+ minReplicas: z.number().int().positive().optional(),
75
+ maxReplicas: z.number().int().positive().optional(),
76
+ targetCPUUtilizationPercentage: z.number().int().positive().optional(),
77
+ })
78
+ .strict();
79
+
80
+ const resourcesSchema = z.object({ cpu: z.string().min(1), memory: z.string().min(1) }).strict();
81
+
82
+ const cacheSchema = z
83
+ .object({
84
+ redis: z
85
+ .object({ enabled: z.boolean(), url: z.string().min(1).optional() })
86
+ .strict()
87
+ .optional(),
88
+ })
89
+ .strict();
90
+
91
+ const networkSchema = z
92
+ .object({
93
+ additionalTcpPorts: z.array(z.number().int().min(1).max(65535)).default([]),
94
+ })
95
+ .strict();
96
+
97
+ const buildContextSchema = z
98
+ .string()
99
+ .min(1)
100
+ .refine((value) => value === ".", { message: BUILD_CONTEXT_CONSTRAINT });
101
+
102
+ /**
103
+ * The standalone `deploy.ts` contract (legacy). Mirrors the registry's
104
+ * `ProviderDeploymentConfigSchema`, including its own defaults — note that a
105
+ * legacy file without `hpa` resolved to `{ enabled: false }`, not the
106
+ * profile HPA, so the two default tables are deliberately different.
107
+ */
108
+ export const legacyDeploymentConfigSchema = z
109
+ .object({
110
+ runtime: z.enum(["shared", "dedicated", "browser"]),
111
+ language: z.enum(["typescript", "python"]),
112
+ replicas: z.number().int().positive().default(1),
113
+ hpa: hpaSchema.default({ enabled: false }),
114
+ resources: resourcesSchema,
115
+ cache: cacheSchema.optional(),
116
+ network: networkSchema.optional(),
117
+ buildContext: buildContextSchema.optional(),
118
+ })
119
+ .strict();
120
+
121
+ /** The authored `deployment` key: every field optional (registry `ProviderDeploymentOverridesSchema`). */
122
+ export const deploymentOverridesSchema = z
123
+ .object({
124
+ runtime: z.enum(["shared", "dedicated", "browser"]).optional(),
125
+ language: z.enum(["typescript", "python"]).optional(),
126
+ replicas: z.number().int().positive().optional(),
127
+ hpa: hpaSchema.optional(),
128
+ resources: resourcesSchema.optional(),
129
+ cache: cacheSchema.optional(),
130
+ network: networkSchema.optional(),
131
+ buildContext: buildContextSchema.optional(),
132
+ })
133
+ .strict();
134
+
135
+ export type DeploymentParse<T> =
136
+ | { readonly ok: true; readonly value: T }
137
+ | { readonly ok: false; readonly reason: string };
138
+
139
+ function formatZodIssues(error: z.ZodError): string {
140
+ return error.issues
141
+ .map((issue) => {
142
+ const path = issue.path.map(String).join(".");
143
+ return path ? `${path}: ${issue.message}` : issue.message;
144
+ })
145
+ .join("; ");
146
+ }
147
+
148
+ /** Parse a legacy `deploy.ts` default export into the resolved view. */
149
+ export function normalizeLegacyDeployment(
150
+ value: unknown,
151
+ ): DeploymentParse<ResolvedDeploymentIntent> {
152
+ const parsed = legacyDeploymentConfigSchema.safeParse(value);
153
+ if (!parsed.success) {
154
+ return {
155
+ ok: false,
156
+ reason: `deploy.ts is not a valid deployment config: ${formatZodIssues(parsed.error)}`,
157
+ };
158
+ }
159
+ const legacy = parsed.data;
160
+ return {
161
+ ok: true,
162
+ value: {
163
+ runtime: legacy.runtime,
164
+ language: legacy.language,
165
+ replicas: legacy.replicas,
166
+ hpa: legacy.hpa,
167
+ resources: legacy.resources,
168
+ ...(legacy.cache ? { cache: legacy.cache } : {}),
169
+ ...(legacy.network ? { network: legacy.network } : {}),
170
+ buildContext: legacy.buildContext ?? DEPLOYMENT_PROFILE_DEFAULTS.buildContext,
171
+ },
172
+ };
173
+ }
174
+
175
+ /** Parse an authored `deployment` key against the strict overrides contract. */
176
+ export function parseDeploymentIntent(
177
+ value: unknown,
178
+ ): DeploymentParse<ProviderDeploymentOverrides> {
179
+ const parsed = deploymentOverridesSchema.safeParse(value);
180
+ if (!parsed.success) {
181
+ return { ok: false, reason: `deployment key is invalid: ${formatZodIssues(parsed.error)}` };
182
+ }
183
+ return { ok: true, value: parsed.data };
184
+ }
185
+
186
+ /**
187
+ * Resolve an authored key against the runtime profiles, per field;
188
+ * `resources` and `hpa` resolve as whole objects (never deep-merged).
189
+ * Throws when the intent cannot resolve (dedicated runtime without
190
+ * resources, non-default buildContext) — the registry rejects the same.
191
+ */
192
+ export function resolveDeploymentIntent(
193
+ intent: ProviderDeploymentOverrides = {},
194
+ ): ResolvedDeploymentIntent {
195
+ const runtime = intent.runtime ?? DEPLOYMENT_PROFILE_DEFAULTS.runtime;
196
+ const resources = intent.resources ?? DEPLOYMENT_PROFILE_DEFAULTS.resources[runtime];
197
+ if (!resources) {
198
+ throw new Error(
199
+ `resources: runtime "${runtime}" has no profile default; declare explicit resources { cpu, memory }`,
200
+ );
201
+ }
202
+ if (
203
+ intent.buildContext !== undefined &&
204
+ intent.buildContext !== DEPLOYMENT_PROFILE_DEFAULTS.buildContext
205
+ ) {
206
+ throw new Error(`buildContext: ${BUILD_CONTEXT_CONSTRAINT}`);
207
+ }
208
+ return {
209
+ runtime,
210
+ language: intent.language ?? DEPLOYMENT_PROFILE_DEFAULTS.language,
211
+ replicas: intent.replicas ?? DEPLOYMENT_PROFILE_DEFAULTS.replicas,
212
+ hpa: intent.hpa ? { ...intent.hpa } : { ...DEPLOYMENT_PROFILE_DEFAULTS.hpa },
213
+ resources: { ...resources },
214
+ ...(intent.cache ? { cache: cloneJson(intent.cache) } : {}),
215
+ ...(intent.network
216
+ ? { network: { additionalTcpPorts: [...(intent.network.additionalTcpPorts ?? [])] } }
217
+ : {}),
218
+ buildContext: intent.buildContext ?? DEPLOYMENT_PROFILE_DEFAULTS.buildContext,
219
+ };
220
+ }
221
+
222
+ /**
223
+ * Two resolved views describe the same deployment when they are deep-equal
224
+ * after dropping empty shells (`network: { additionalTcpPorts: [] }`,
225
+ * `cache: {}`) that carry no intent — the manifests they render are
226
+ * byte-identical.
227
+ */
228
+ export function deploymentIntentsEquivalent(
229
+ left: ResolvedDeploymentIntent,
230
+ right: ResolvedDeploymentIntent,
231
+ ): boolean {
232
+ return deepEqual(canonicalResolvedDeployment(left), canonicalResolvedDeployment(right));
233
+ }
234
+
235
+ export function canonicalResolvedDeployment(
236
+ resolved: ResolvedDeploymentIntent,
237
+ ): ResolvedDeploymentIntent {
238
+ const { cache, network, ...rest } = resolved;
239
+ const canonical: ResolvedDeploymentIntent = { ...rest };
240
+ if (cache?.redis !== undefined) canonical.cache = { redis: { ...cache.redis } };
241
+ if (network !== undefined && network.additionalTcpPorts.length > 0) {
242
+ canonical.network = { additionalTcpPorts: [...network.additionalTcpPorts] };
243
+ }
244
+ return canonical;
245
+ }
246
+
247
+ /**
248
+ * The smallest `deployment` key that resolves to `resolved`: profile
249
+ * defaults are omitted, `hpa`/`resources` are kept whole when they differ
250
+ * (the resolver never deep-merges them), and empty shells are dropped.
251
+ * Callers prove the result with
252
+ * `deploymentIntentsEquivalent(resolveDeploymentIntent(key), resolved)`.
253
+ */
254
+ export function subtractDeploymentDefaults(
255
+ resolved: ResolvedDeploymentIntent,
256
+ ): ProviderDeploymentOverrides {
257
+ const intent: ProviderDeploymentOverrides = {};
258
+ if (resolved.runtime !== DEPLOYMENT_PROFILE_DEFAULTS.runtime) intent.runtime = resolved.runtime;
259
+ if (resolved.language !== DEPLOYMENT_PROFILE_DEFAULTS.language)
260
+ intent.language = resolved.language;
261
+ if (resolved.replicas !== DEPLOYMENT_PROFILE_DEFAULTS.replicas)
262
+ intent.replicas = resolved.replicas;
263
+ if (!deepEqual(resolved.hpa, DEPLOYMENT_PROFILE_DEFAULTS.hpa)) intent.hpa = { ...resolved.hpa };
264
+ const profileResources = DEPLOYMENT_PROFILE_DEFAULTS.resources[resolved.runtime];
265
+ if (profileResources === undefined || !deepEqual(resolved.resources, profileResources)) {
266
+ intent.resources = { ...resolved.resources };
267
+ }
268
+ if (resolved.cache?.redis !== undefined) intent.cache = { redis: { ...resolved.cache.redis } };
269
+ if (resolved.network !== undefined && resolved.network.additionalTcpPorts.length > 0) {
270
+ intent.network = { additionalTcpPorts: [...resolved.network.additionalTcpPorts] };
271
+ }
272
+ // buildContext: "." is the only accepted value, so it is never authored.
273
+ return intent;
274
+ }
275
+
276
+ /** Authored order for emitted keys: the registry contract's field order. */
277
+ export const DEPLOYMENT_INTENT_FIELD_ORDER: readonly (keyof ProviderDeploymentOverrides)[] = [
278
+ "runtime",
279
+ "language",
280
+ "replicas",
281
+ "hpa",
282
+ "resources",
283
+ "cache",
284
+ "network",
285
+ "buildContext",
286
+ ];
287
+
288
+ export interface RedundantDeploymentField {
289
+ /** Dotted path under `deployment`, e.g. `hpa` or `network.additionalTcpPorts`. */
290
+ readonly path: string;
291
+ readonly message: string;
292
+ }
293
+
294
+ /**
295
+ * Fields of an authored `deployment` key that restate what the runtime
296
+ * profile already resolves (ADR-0009 "derived values are not re-stated").
297
+ * Accepts an unvalidated value because `apifuse check` inspects the loaded
298
+ * definition, whose key the SDK passes through verbatim.
299
+ */
300
+ export function redundantDeploymentDefaults(intent: unknown): RedundantDeploymentField[] {
301
+ if (!isRecord(intent)) return [];
302
+ const redundant: RedundantDeploymentField[] = [];
303
+ const flag = (path: string, detail: string): void => {
304
+ redundant.push({ path, message: `deployment.${path} ${detail}; omit it` });
305
+ };
306
+ if (intent.runtime === DEPLOYMENT_PROFILE_DEFAULTS.runtime) {
307
+ flag("runtime", `restates the profile default ("${DEPLOYMENT_PROFILE_DEFAULTS.runtime}")`);
308
+ }
309
+ if (intent.language === DEPLOYMENT_PROFILE_DEFAULTS.language) {
310
+ flag("language", `restates the profile default ("${DEPLOYMENT_PROFILE_DEFAULTS.language}")`);
311
+ }
312
+ if (intent.replicas === DEPLOYMENT_PROFILE_DEFAULTS.replicas) {
313
+ flag("replicas", `restates the profile default (${DEPLOYMENT_PROFILE_DEFAULTS.replicas})`);
314
+ }
315
+ if (deepEqual(intent.hpa, DEPLOYMENT_PROFILE_DEFAULTS.hpa)) {
316
+ flag("hpa", "restates the profile default (enabled, 1-1 replicas, 70% CPU target)");
317
+ }
318
+ const runtime =
319
+ typeof intent.runtime === "string" && intent.runtime in DEPLOYMENT_PROFILE_DEFAULTS.resources
320
+ ? (intent.runtime as DeploymentRuntime)
321
+ : DEPLOYMENT_PROFILE_DEFAULTS.runtime;
322
+ const profileResources = DEPLOYMENT_PROFILE_DEFAULTS.resources[runtime];
323
+ if (profileResources !== undefined && deepEqual(intent.resources, profileResources)) {
324
+ flag(
325
+ "resources",
326
+ `restates the "${runtime}" profile default (${profileResources.cpu}/${profileResources.memory})`,
327
+ );
328
+ }
329
+ if (intent.buildContext === DEPLOYMENT_PROFILE_DEFAULTS.buildContext) {
330
+ flag("buildContext", 'restates the only accepted value (".")');
331
+ }
332
+ if (isRecord(intent.network)) {
333
+ const ports = intent.network.additionalTcpPorts;
334
+ if (ports === undefined || (Array.isArray(ports) && ports.length === 0)) {
335
+ flag("network", "declares no additional TCP ports (empty shell)");
336
+ }
337
+ }
338
+ if (isRecord(intent.cache) && intent.cache.redis === undefined) {
339
+ flag("cache", "declares no redis intent (empty shell)");
340
+ }
341
+ return redundant;
342
+ }
343
+
344
+ /** Structural equality for JSON-shaped values, key order insensitive. */
345
+ export function deepEqual(left: unknown, right: unknown): boolean {
346
+ if (left === right) return true;
347
+ if (Array.isArray(left) || Array.isArray(right)) {
348
+ if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) return false;
349
+ return left.every((item, index) => deepEqual(item, right[index]));
350
+ }
351
+ if (!isRecord(left) || !isRecord(right)) return false;
352
+ const leftKeys = Object.keys(left).filter((key) => left[key] !== undefined);
353
+ const rightKeys = Object.keys(right).filter((key) => right[key] !== undefined);
354
+ if (leftKeys.length !== rightKeys.length) return false;
355
+ return leftKeys.every((key) => Object.hasOwn(right, key) && deepEqual(left[key], right[key]));
356
+ }
357
+
358
+ function isRecord(value: unknown): value is Record<string, unknown> {
359
+ return typeof value === "object" && value !== null && !Array.isArray(value);
360
+ }
361
+
362
+ function cloneJson<T>(value: T): T {
363
+ return JSON.parse(JSON.stringify(value)) as T;
364
+ }
@@ -0,0 +1,221 @@
1
+ import type { AuthMode, ProviderDefinition } from "../types.js";
2
+
3
+ /**
4
+ * The connection the local CLIs stand in for the gateway with.
5
+ *
6
+ * At invocation time the gateway resolves the credential a provider needs and
7
+ * attaches it to the request envelope as
8
+ * `connection: { id, mode, secrets, metadata }`; `serve` then builds
9
+ * `ctx.credential` from `connection.secrets` and nothing else. For
10
+ * `auth.mode: "platform-managed"` the secrets are the platform-owned key the
11
+ * caller never sees — which is why a probe reaches one only by going back
12
+ * through the gateway (`ctx.gateway.execute(...)` in a health case's
13
+ * `prepareInput`), and why nothing that runs outside the gateway had any way
14
+ * to supply it.
15
+ *
16
+ * `apifuse record` hard-coded `credential: { mode: "none" }`, so
17
+ * `ctx.credential.get(...)` returned `undefined` for every platform-managed
18
+ * provider and the run died on that provider's own `MISSING_SECRET`. The same
19
+ * hole made `submit-check --smoke` POST an envelope with no `connection` at
20
+ * all. A large share of the fleet was unrecordable and unsmokeable, and it
21
+ * read as "no live upstream success" rather than as a missing capability.
22
+ *
23
+ * This module is the local resolver for that connection. It does not invent a
24
+ * second credential path: it produces the exact shape the gateway injects, so
25
+ * the provider code under test takes the production branch.
26
+ */
27
+ export interface LocalConnection {
28
+ readonly id: string;
29
+ readonly mode: AuthMode;
30
+ readonly secrets: Record<string, string>;
31
+ readonly metadata: Record<string, never>;
32
+ /**
33
+ * Empty, exactly as the gateway leaves it when it injects a platform
34
+ * credential. `OperationConnectionSchema` requires the field, so omitting
35
+ * it would make every smoke envelope fail request validation before the
36
+ * provider ran.
37
+ */
38
+ readonly externalRef: string;
39
+ }
40
+
41
+ /**
42
+ * JSON object of `connection.secrets`, keyed exactly as the provider reads
43
+ * them through `ctx.credential.get(...)`.
44
+ *
45
+ * A single JSON value rather than one variable per key on purpose:
46
+ * platform-managed providers must not declare `credential.keys` (the SDK lint
47
+ * rejects it), so the key names are known only to the provider's own source.
48
+ * There is no derivation from an env name that would be right for every
49
+ * provider, and guessing one would be a second, lossy contract next to the
50
+ * gateway's.
51
+ */
52
+ export const LOCAL_CONNECTION_SECRETS_ENV = "APIFUSE__LOCAL_CONNECTION__SECRETS";
53
+
54
+ /** Stable local connection id, mirroring the CLIs' other `local-*` scopes. */
55
+ export const LOCAL_CONNECTION_ID = "local-connection";
56
+
57
+ /** Auth modes whose providers read a credential the gateway supplies. */
58
+ export function providerRequiresConnection(provider: {
59
+ readonly auth?: { readonly mode?: AuthMode } | undefined;
60
+ }): boolean {
61
+ const mode = provider.auth?.mode;
62
+ return mode !== undefined && mode !== "none";
63
+ }
64
+
65
+ export type CredentialOverrideParse =
66
+ | { readonly ok: true; readonly secrets: Record<string, string> }
67
+ | { readonly ok: false; readonly reason: string };
68
+
69
+ /**
70
+ * Parses repeated `--credential key=value` arguments.
71
+ *
72
+ * Splits on the first `=` only: a base64 or URL-shaped secret routinely
73
+ * contains more.
74
+ */
75
+ export function parseCredentialOverrides(values: readonly string[]): CredentialOverrideParse {
76
+ const secrets: Record<string, string> = {};
77
+ for (const [index, value] of values.entries()) {
78
+ // The offending argument is never echoed. `--credential =secret` and
79
+ // `--credential secret` are both malformed *and* carry the credential, so
80
+ // quoting the input to be helpful would print it to stderr — before any
81
+ // redaction context exists, so no caller could scrub it.
82
+ const separator = value.indexOf("=");
83
+ if (separator <= 0) {
84
+ return {
85
+ ok: false,
86
+ reason: `--credential #${index + 1} is not of the form key=value; its value is not echoed here because it may be the credential.`,
87
+ };
88
+ }
89
+ const key = value.slice(0, separator).trim();
90
+ if (key.length === 0) {
91
+ return {
92
+ ok: false,
93
+ reason: `--credential #${index + 1} has an empty key; its value is not echoed here because it may be the credential.`,
94
+ };
95
+ }
96
+ secrets[key] = value.slice(separator + 1);
97
+ }
98
+ return { ok: true, secrets };
99
+ }
100
+
101
+ /** Reads {@link LOCAL_CONNECTION_SECRETS_ENV} into a secrets map. */
102
+ export function parseEnvironmentSecrets(raw: string | undefined): CredentialOverrideParse {
103
+ if (raw === undefined || raw.trim().length === 0) {
104
+ return { ok: true, secrets: {} };
105
+ }
106
+ let parsed: unknown;
107
+ try {
108
+ parsed = JSON.parse(raw);
109
+ } catch (error) {
110
+ return {
111
+ ok: false,
112
+ reason: `${LOCAL_CONNECTION_SECRETS_ENV} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
113
+ };
114
+ }
115
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
116
+ return {
117
+ ok: false,
118
+ reason: `${LOCAL_CONNECTION_SECRETS_ENV} must be a JSON object of credential key to string value.`,
119
+ };
120
+ }
121
+ const secrets: Record<string, string> = {};
122
+ for (const [key, value] of Object.entries(parsed)) {
123
+ if (typeof value !== "string") {
124
+ return {
125
+ ok: false,
126
+ reason: `${LOCAL_CONNECTION_SECRETS_ENV}.${key} must be a string (received ${typeof value}); the value is not echoed here.`,
127
+ };
128
+ }
129
+ secrets[key] = value;
130
+ }
131
+ return { ok: true, secrets };
132
+ }
133
+
134
+ export interface ResolveLocalConnectionOptions {
135
+ /** Repeated `--credential key=value` arguments, in order. */
136
+ readonly overrides?: readonly string[];
137
+ /** Environment to read {@link LOCAL_CONNECTION_SECRETS_ENV} from. */
138
+ readonly env?: Readonly<Record<string, string | undefined>>;
139
+ }
140
+
141
+ export type LocalConnectionResolution =
142
+ | { readonly ok: true; readonly connection: LocalConnection | undefined }
143
+ | { readonly ok: false; readonly reason: string };
144
+
145
+ /**
146
+ * Resolves the connection to attach for one local invocation.
147
+ *
148
+ * Three outcomes, and the middle one is the point of the change:
149
+ *
150
+ * - the provider needs no credential (`auth.mode` absent or `"none"`) →
151
+ * no connection, exactly as before;
152
+ * - the provider needs one and none is configured → `ok: false` with a
153
+ * message naming both ways to supply it. The caller surfaces that instead
154
+ * of letting the provider fail deep inside a handler on a `MISSING_SECRET`
155
+ * that reads like an upstream problem;
156
+ * - the provider needs one and it is configured → the gateway's envelope
157
+ * shape.
158
+ *
159
+ * CLI overrides win over the environment so a one-off run does not need the
160
+ * shell variable unset.
161
+ */
162
+ export function resolveLocalConnection(
163
+ provider: Pick<ProviderDefinition, "id"> & { auth?: { mode?: AuthMode } },
164
+ options: ResolveLocalConnectionOptions = {},
165
+ ): LocalConnectionResolution {
166
+ const fromEnv = parseEnvironmentSecrets(
167
+ (options.env ?? process.env)[LOCAL_CONNECTION_SECRETS_ENV],
168
+ );
169
+ if (!fromEnv.ok) return fromEnv;
170
+
171
+ const fromArgs = parseCredentialOverrides(options.overrides ?? []);
172
+ if (!fromArgs.ok) return fromArgs;
173
+
174
+ const secrets = { ...fromEnv.secrets, ...fromArgs.secrets };
175
+ const mode = provider.auth?.mode;
176
+
177
+ if (!providerRequiresConnection(provider)) {
178
+ if (Object.keys(secrets).length > 0) {
179
+ return {
180
+ ok: false,
181
+ reason: `Provider "${provider.id}" declares auth.mode ${JSON.stringify(mode ?? "none")}, which takes no credential. Remove the supplied credential values.`,
182
+ };
183
+ }
184
+ return { ok: true, connection: undefined };
185
+ }
186
+
187
+ if (Object.keys(secrets).length === 0) {
188
+ return {
189
+ ok: false,
190
+ reason: missingLocalConnectionMessage(provider.id, mode ?? "none"),
191
+ };
192
+ }
193
+
194
+ return {
195
+ ok: true,
196
+ connection: {
197
+ id: LOCAL_CONNECTION_ID,
198
+ // `mode` is narrowed by providerRequiresConnection above.
199
+ mode: mode ?? "none",
200
+ secrets,
201
+ metadata: {},
202
+ externalRef: "",
203
+ },
204
+ };
205
+ }
206
+
207
+ /** The message a caller prints when a needed credential is not configured. */
208
+ export function missingLocalConnectionMessage(providerId: string, mode: AuthMode): string {
209
+ const platformManaged = mode === "platform-managed";
210
+ return [
211
+ `Provider "${providerId}" declares auth.mode "${mode}", so the gateway injects a credential on every invocation and this command has none.`,
212
+ platformManaged
213
+ ? "The value is the platform-owned key an operator holds; it is not a provider secret and is not derivable from the checkout."
214
+ : "Supply the same credential the gateway would resolve for a connection.",
215
+ "Supply it with one of:",
216
+ " --credential <key>=<value> (repeatable)",
217
+ ` ${LOCAL_CONNECTION_SECRETS_ENV}='{"<key>":"<value>"}'`,
218
+ "The keys are the ones the provider passes to ctx.credential.get(...).",
219
+ "Pass --no-credential to run without one anyway (the provider will fail the way it does in production when the credential is unavailable).",
220
+ ].join("\n");
221
+ }