@apifuse/provider-sdk 2.2.0-beta.5 → 2.2.0-beta.51

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 (368) hide show
  1. package/AUTHORING.md +537 -33
  2. package/CHANGELOG.md +205 -1
  3. package/README.md +83 -22
  4. package/SUBMISSION.md +2 -2
  5. package/bin/apifuse-check.ts +165 -11
  6. package/bin/apifuse-dev.ts +57 -13
  7. package/bin/apifuse-migrate-operation-declaration.ts +55 -0
  8. package/bin/apifuse-migrate-shape.ts +202 -0
  9. package/bin/apifuse-pack-check.ts +22 -2
  10. package/bin/apifuse-pack-smoke.ts +57 -2
  11. package/bin/apifuse-pack-types.ts +357 -38
  12. package/bin/apifuse-perf.ts +14 -13
  13. package/bin/apifuse-record.ts +709 -72
  14. package/bin/apifuse-submit-check.ts +2344 -324
  15. package/bin/apifuse-sync-assets.ts +117 -0
  16. package/bin/submit-check-delimited-text.ts +50 -0
  17. package/dist/auth-turn/index.d.ts +3 -3
  18. package/dist/auth-turn/index.js +1 -1
  19. package/dist/auth.d.ts +14 -0
  20. package/dist/auth.js +67 -0
  21. package/dist/ceremonies/index.d.ts +16 -0
  22. package/dist/ceremonies/index.js +141 -36
  23. package/dist/cli/commands.d.ts +1 -1
  24. package/dist/cli/commands.js +27 -0
  25. package/dist/cli/create.d.ts +4 -1
  26. package/dist/cli/create.js +42 -37
  27. package/dist/cli/migrate-operation-declaration.d.ts +59 -0
  28. package/dist/cli/migrate-operation-declaration.js +1249 -0
  29. package/dist/cli/migrate-operation-shape.d.ts +44 -0
  30. package/dist/cli/migrate-operation-shape.js +113 -0
  31. package/dist/cli/migrate-provider-shape.d.ts +52 -0
  32. package/dist/cli/migrate-provider-shape.js +578 -0
  33. package/dist/cli/prompt-assets.d.ts +80 -0
  34. package/dist/cli/prompt-assets.js +743 -0
  35. package/dist/cli/templates/provider/AGENTS.md.tpl +17 -8
  36. package/dist/cli/templates/provider/Dockerfile.tpl +1 -1
  37. package/dist/cli/templates/provider/README.md.tpl +5 -5
  38. package/dist/cli/templates/provider/index.ts.tpl +6 -3
  39. package/dist/cli/templates/provider/operations/ping.ts.tpl +4 -1
  40. package/dist/cli/templates/provider/provider.json.tpl +6 -0
  41. package/dist/config/loader.d.ts +179 -16
  42. package/dist/config/loader.js +435 -127
  43. package/dist/contract-serialization.js +4 -8
  44. package/dist/contract-types.d.ts +12 -5
  45. package/dist/contract.js +24 -10
  46. package/dist/declaration-validation.d.ts +33 -0
  47. package/dist/declaration-validation.js +266 -0
  48. package/dist/define.d.ts +66 -29
  49. package/dist/define.js +778 -69
  50. package/dist/dev.d.ts +3 -0
  51. package/dist/dev.js +1 -1
  52. package/dist/engine.d.ts +78 -0
  53. package/dist/engine.js +133 -0
  54. package/dist/error-observability.d.ts +7 -0
  55. package/dist/error-observability.js +61 -0
  56. package/dist/error-resolution.d.ts +4 -0
  57. package/dist/error-resolution.js +122 -0
  58. package/dist/errors.d.ts +33 -0
  59. package/dist/errors.js +40 -0
  60. package/dist/fixture-sanitization.d.ts +28 -0
  61. package/dist/fixture-sanitization.js +227 -0
  62. package/dist/health-scenario.d.ts +1842 -0
  63. package/dist/health-scenario.js +624 -0
  64. package/dist/index.d.ts +21 -10
  65. package/dist/index.js +12 -7
  66. package/dist/lint.d.ts +23 -11
  67. package/dist/lint.js +572 -69
  68. package/dist/native-address.d.ts +43 -0
  69. package/dist/native-address.js +281 -0
  70. package/dist/native-egress-policy.d.ts +31 -0
  71. package/dist/native-egress-policy.js +288 -0
  72. package/dist/observability.d.ts +5 -2
  73. package/dist/observability.js +48 -1
  74. package/dist/provider.d.ts +10 -2
  75. package/dist/provider.js +4 -1
  76. package/dist/runtime/auth-flow.d.ts +5 -1
  77. package/dist/runtime/auth-flow.js +6 -0
  78. package/dist/runtime/browser.d.ts +1 -0
  79. package/dist/runtime/browser.js +492 -49
  80. package/dist/runtime/cache.d.ts +1 -0
  81. package/dist/runtime/cache.js +169 -15
  82. package/dist/runtime/choice-wordlist.d.ts +9 -0
  83. package/dist/runtime/choice-wordlist.js +138 -0
  84. package/dist/runtime/choice.d.ts +13 -1
  85. package/dist/runtime/choice.js +490 -102
  86. package/dist/runtime/chrome149-header-order.d.ts +58 -0
  87. package/dist/runtime/chrome149-header-order.js +289 -0
  88. package/dist/runtime/env.js +12 -0
  89. package/dist/runtime/executor.d.ts +3 -2
  90. package/dist/runtime/executor.js +26 -25
  91. package/dist/runtime/http.d.ts +1 -0
  92. package/dist/runtime/http.js +515 -53
  93. package/dist/runtime/insights.js +2 -2
  94. package/dist/runtime/instrumentation.d.ts +2 -2
  95. package/dist/runtime/instrumentation.js +366 -8
  96. package/dist/runtime/native-network-errors.d.ts +33 -0
  97. package/dist/runtime/native-network-errors.js +69 -0
  98. package/dist/runtime/native-network.d.ts +96 -0
  99. package/dist/runtime/native-network.js +1232 -0
  100. package/dist/runtime/ocr.d.ts +29 -0
  101. package/dist/runtime/ocr.js +440 -0
  102. package/dist/runtime/otlp.d.ts +71 -2
  103. package/dist/runtime/otlp.js +397 -16
  104. package/dist/runtime/proxy-errors.js +6 -2
  105. package/dist/runtime/proxy-nodemaven.d.ts +56 -0
  106. package/dist/runtime/proxy-nodemaven.js +146 -0
  107. package/dist/runtime/proxy-telemetry.d.ts +80 -1
  108. package/dist/runtime/proxy-telemetry.js +154 -47
  109. package/dist/runtime/redirects.d.ts +29 -0
  110. package/dist/runtime/redirects.js +36 -0
  111. package/dist/runtime/redis.d.ts +1 -1
  112. package/dist/runtime/redis.js +4 -2
  113. package/dist/runtime/request-options.d.ts +68 -1
  114. package/dist/runtime/request-options.js +548 -0
  115. package/dist/runtime/resolver-config.d.ts +6 -0
  116. package/dist/runtime/resolver-config.js +6 -0
  117. package/dist/runtime/resolver-public.d.ts +1 -0
  118. package/dist/runtime/resolver-public.js +1 -0
  119. package/dist/runtime/resolver-shared.d.ts +14 -0
  120. package/dist/runtime/resolver-shared.js +12 -0
  121. package/dist/runtime/resolver-vendors/bindings.d.ts +48 -0
  122. package/dist/runtime/resolver-vendors/bindings.js +40 -0
  123. package/dist/runtime/resolver-vendors/browser.d.ts +22 -0
  124. package/dist/runtime/resolver-vendors/browser.js +377 -0
  125. package/dist/runtime/resolver-vendors/capsolver.d.ts +22 -0
  126. package/dist/runtime/resolver-vendors/capsolver.js +531 -0
  127. package/dist/runtime/resolver-vendors/hosts.d.ts +2 -0
  128. package/dist/runtime/resolver-vendors/hosts.js +33 -0
  129. package/dist/runtime/resolver-vendors/twocaptcha.d.ts +24 -0
  130. package/dist/runtime/resolver-vendors/twocaptcha.js +408 -0
  131. package/dist/runtime/resolver-vendors/types.d.ts +94 -0
  132. package/dist/runtime/resolver-vendors/types.js +96 -0
  133. package/dist/runtime/resolver.d.ts +72 -0
  134. package/dist/runtime/resolver.js +771 -0
  135. package/dist/runtime/secrets.d.ts +27 -0
  136. package/dist/runtime/secrets.js +51 -0
  137. package/dist/runtime/state.d.ts +3 -0
  138. package/dist/runtime/state.js +277 -71
  139. package/dist/runtime/stealth-cookies.d.ts +20 -0
  140. package/dist/runtime/stealth-cookies.js +111 -0
  141. package/dist/runtime/stealth.d.ts +41 -5
  142. package/dist/runtime/stealth.js +997 -291
  143. package/dist/runtime/stt.js +1 -12
  144. package/dist/runtime/timeout.d.ts +5 -0
  145. package/dist/runtime/timeout.js +12 -0
  146. package/dist/runtime/trace-config.d.ts +12 -0
  147. package/dist/runtime/trace-config.js +62 -0
  148. package/dist/runtime/trace.d.ts +5 -0
  149. package/dist/runtime/trace.js +43 -10
  150. package/dist/serve.d.ts +1 -1
  151. package/dist/serve.js +1 -1
  152. package/dist/server/error-observability.d.ts +1 -0
  153. package/dist/server/error-observability.js +1 -0
  154. package/dist/server/index.d.ts +5 -2
  155. package/dist/server/index.js +2 -2
  156. package/dist/server/self-test-input-tokens.d.ts +2 -1
  157. package/dist/server/self-test-input-tokens.js +18 -14
  158. package/dist/server/self-test.d.ts +14 -3
  159. package/dist/server/self-test.js +129 -58
  160. package/dist/server/serve-implementation.d.ts +230 -0
  161. package/dist/server/serve-implementation.js +2265 -0
  162. package/dist/server/serve.d.ts +1 -70
  163. package/dist/server/serve.js +1 -1131
  164. package/dist/server/trace-output.d.ts +6 -0
  165. package/dist/server/trace-output.js +79 -0
  166. package/dist/server/types.d.ts +30 -5
  167. package/dist/server/types.js +13 -1
  168. package/dist/stateful/errors.d.ts +19 -0
  169. package/dist/stateful/errors.js +24 -0
  170. package/dist/stateful/http-provider-event-emitter.d.ts +40 -0
  171. package/dist/stateful/http-provider-event-emitter.js +237 -0
  172. package/dist/stateful/http-session-owner-registry.d.ts +44 -0
  173. package/dist/stateful/http-session-owner-registry.js +210 -0
  174. package/dist/stateful/index.d.ts +18 -0
  175. package/dist/stateful/index.js +18 -0
  176. package/dist/stateful/provider-event-delivery-failures.d.ts +32 -0
  177. package/dist/stateful/provider-event-delivery-failures.js +43 -0
  178. package/dist/stateful/provider-event-pipeline-metrics.d.ts +46 -0
  179. package/dist/stateful/provider-event-pipeline-metrics.js +48 -0
  180. package/dist/stateful/provider-event-pipeline.d.ts +50 -0
  181. package/dist/stateful/provider-event-pipeline.js +1 -0
  182. package/dist/stateful/provider-events.d.ts +101 -0
  183. package/dist/stateful/provider-events.js +289 -0
  184. package/dist/stateful/session-key.d.ts +15 -0
  185. package/dist/stateful/session-key.js +86 -0
  186. package/dist/stateful/stateful-provider-adapter-context.d.ts +5 -0
  187. package/dist/stateful/stateful-provider-adapter-context.js +42 -0
  188. package/dist/stateful/stateful-provider-adapter-metrics.d.ts +15 -0
  189. package/dist/stateful/stateful-provider-adapter-metrics.js +21 -0
  190. package/dist/stateful/stateful-provider-adapter.d.ts +98 -0
  191. package/dist/stateful/stateful-provider-adapter.js +287 -0
  192. package/dist/stateful/stateful-provider-observability.d.ts +62 -0
  193. package/dist/stateful/stateful-provider-observability.js +161 -0
  194. package/dist/stateful/stateful-provider-owner-forwarder.d.ts +41 -0
  195. package/dist/stateful/stateful-provider-owner-forwarder.js +215 -0
  196. package/dist/stateful/stateful-provider-runtime-context.d.ts +32 -0
  197. package/dist/stateful/stateful-provider-runtime-context.js +60 -0
  198. package/dist/stateful/stateful-provider-runtime-executor.d.ts +34 -0
  199. package/dist/stateful/stateful-provider-runtime-executor.js +52 -0
  200. package/dist/stateful/stateful-provider-session-routing.d.ts +67 -0
  201. package/dist/stateful/stateful-provider-session-routing.js +345 -0
  202. package/dist/stateful/stateful-provider-session-runtime.d.ts +98 -0
  203. package/dist/stateful/stateful-provider-session-runtime.js +245 -0
  204. package/dist/stateful-signing.d.ts +18 -0
  205. package/dist/stateful-signing.js +27 -0
  206. package/dist/stealth/profiles.d.ts +9 -4
  207. package/dist/stealth/profiles.js +160 -211
  208. package/dist/stream-evidence.d.ts +74 -0
  209. package/dist/stream-evidence.js +785 -0
  210. package/dist/stream.js +7 -1
  211. package/dist/testing/index.d.ts +2 -1
  212. package/dist/testing/index.js +2 -1
  213. package/dist/testing/run.d.ts +32 -2
  214. package/dist/testing/run.js +489 -21
  215. package/dist/trace-sanitization.d.ts +5 -0
  216. package/dist/trace-sanitization.js +45 -0
  217. package/dist/types.d.ts +673 -131
  218. package/dist/types.js +1 -0
  219. package/package.json +45 -5
  220. package/src/auth-turn/index.ts +1 -1
  221. package/src/auth.ts +118 -0
  222. package/src/ceremonies/index.ts +189 -46
  223. package/src/cli/__tests__/fixtures/migrate-operation-declaration/approval-override.ts.txt +6 -0
  224. package/src/cli/__tests__/fixtures/migrate-operation-declaration/codemod-syntax.ts.txt +3 -0
  225. package/src/cli/__tests__/fixtures/migrate-operation-declaration/connection-precedence.ts.txt +10 -0
  226. package/src/cli/__tests__/fixtures/migrate-operation-declaration/docs-conflict.ts.txt +8 -0
  227. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-hoisted-array-spread.ts.txt +15 -0
  228. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-imported-array-spread.ts.txt +9 -0
  229. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-map.ts.txt +5 -0
  230. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-mixed-array-spread.ts.txt +24 -0
  231. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-operation.ts.txt +16 -0
  232. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-map.ts.txt +3 -0
  233. package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoist-all.ts.txt +31 -0
  234. package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoisted-const.ts.txt +11 -0
  235. package/src/cli/__tests__/fixtures/migrate-operation-declaration/imported-spread.ts.txt +11 -0
  236. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-map.ts.txt +11 -0
  237. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-cast-tail.ts.txt +21 -0
  238. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-ekitan.ts.txt +11 -0
  239. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-override.ts.txt +14 -0
  240. package/src/cli/__tests__/fixtures/migrate-operation-declaration/missing-english-locale.ts.txt +7 -0
  241. package/src/cli/__tests__/fixtures/migrate-operation-declaration/no-safety.ts.txt +6 -0
  242. package/src/cli/__tests__/fixtures/migrate-operation-declaration/non-literal.ts.txt +7 -0
  243. package/src/cli/__tests__/fixtures/migrate-operation-declaration/redundant-approval.ts.txt +6 -0
  244. package/src/cli/__tests__/fixtures/migrate-operation-declaration/safety-conflict.ts.txt +7 -0
  245. package/src/cli/__tests__/fixtures/migrate-operation-declaration/stream.ts.txt +7 -0
  246. package/src/cli/__tests__/fixtures/migrate-operation-declaration/tool-router-spread.ts.txt +15 -0
  247. package/src/cli/__tests__/fixtures/migrate-operation-declaration/unparseable.ts.txt +4 -0
  248. package/src/cli/__tests__/fixtures/migrate-operation-declaration/verbatim-template.ts.txt +12 -0
  249. package/src/cli/commands.ts +33 -0
  250. package/src/cli/create.ts +50 -37
  251. package/src/cli/migrate-operation-declaration.ts +1751 -0
  252. package/src/cli/migrate-operation-shape.ts +184 -0
  253. package/src/cli/migrate-provider-shape.ts +772 -0
  254. package/src/cli/prompt-assets.ts +865 -0
  255. package/src/cli/templates/provider/AGENTS.md.tpl +17 -8
  256. package/src/cli/templates/provider/Dockerfile.tpl +1 -1
  257. package/src/cli/templates/provider/README.md.tpl +5 -5
  258. package/src/cli/templates/provider/index.ts.tpl +6 -3
  259. package/src/cli/templates/provider/operations/ping.ts.tpl +4 -1
  260. package/src/cli/templates/provider/provider.json.tpl +6 -0
  261. package/src/config/loader.ts +690 -163
  262. package/src/contract-serialization.ts +5 -7
  263. package/src/contract-types.ts +12 -5
  264. package/src/contract.ts +24 -10
  265. package/src/declaration-validation.ts +330 -0
  266. package/src/define.ts +1048 -131
  267. package/src/dev.ts +4 -1
  268. package/src/engine.ts +279 -0
  269. package/src/error-observability.ts +64 -0
  270. package/src/error-resolution.ts +127 -0
  271. package/src/errors.ts +68 -0
  272. package/src/fixture-sanitization.ts +264 -0
  273. package/src/health-scenario.ts +875 -0
  274. package/src/index.ts +220 -13
  275. package/src/lint.ts +698 -90
  276. package/src/native-address.ts +340 -0
  277. package/src/native-egress-policy.ts +358 -0
  278. package/src/observability.ts +51 -1
  279. package/src/provider.ts +161 -3
  280. package/src/runtime/auth-flow.ts +12 -0
  281. package/src/runtime/browser.ts +661 -63
  282. package/src/runtime/cache.ts +189 -14
  283. package/src/runtime/choice-wordlist.ts +145 -0
  284. package/src/runtime/choice.ts +631 -120
  285. package/src/runtime/chrome149-header-order.ts +330 -0
  286. package/src/runtime/env.ts +13 -0
  287. package/src/runtime/executor.ts +43 -31
  288. package/src/runtime/http.ts +641 -61
  289. package/src/runtime/insights.ts +2 -2
  290. package/src/runtime/instrumentation.ts +520 -15
  291. package/src/runtime/native-network-errors.ts +99 -0
  292. package/src/runtime/native-network.ts +1605 -0
  293. package/src/runtime/ocr.ts +523 -0
  294. package/src/runtime/otlp.ts +467 -21
  295. package/src/runtime/proxy-errors.ts +12 -4
  296. package/src/runtime/proxy-nodemaven.ts +221 -0
  297. package/src/runtime/proxy-telemetry.ts +244 -75
  298. package/src/runtime/redirects.ts +66 -0
  299. package/src/runtime/redis.ts +7 -2
  300. package/src/runtime/request-options.ts +680 -1
  301. package/src/runtime/resolver-config.ts +6 -0
  302. package/src/runtime/resolver-public.ts +23 -0
  303. package/src/runtime/resolver-shared.ts +33 -0
  304. package/src/runtime/resolver-vendors/bindings.ts +56 -0
  305. package/src/runtime/resolver-vendors/browser.ts +533 -0
  306. package/src/runtime/resolver-vendors/capsolver.ts +707 -0
  307. package/src/runtime/resolver-vendors/hosts.ts +38 -0
  308. package/src/runtime/resolver-vendors/twocaptcha.ts +540 -0
  309. package/src/runtime/resolver-vendors/types.ts +212 -0
  310. package/src/runtime/resolver.ts +1157 -0
  311. package/src/runtime/secrets.ts +64 -0
  312. package/src/runtime/state.ts +394 -77
  313. package/src/runtime/stealth-cookies.ts +132 -0
  314. package/src/runtime/stealth.ts +1280 -336
  315. package/src/runtime/stt.ts +1 -19
  316. package/src/runtime/timeout.ts +18 -0
  317. package/src/runtime/trace-config.ts +78 -0
  318. package/src/runtime/trace.ts +57 -17
  319. package/src/serve.ts +6 -1
  320. package/src/server/error-observability.ts +1 -0
  321. package/src/server/index.ts +34 -2
  322. package/src/server/self-test-input-tokens.ts +29 -14
  323. package/src/server/self-test.ts +191 -68
  324. package/src/server/serve-implementation.ts +3378 -0
  325. package/src/server/serve.ts +1 -1632
  326. package/src/server/trace-output.ts +129 -0
  327. package/src/server/types.ts +13 -1
  328. package/src/stateful/README.md +146 -0
  329. package/src/stateful/errors.ts +35 -0
  330. package/src/stateful/http-provider-event-emitter.ts +314 -0
  331. package/src/stateful/http-session-owner-registry.ts +306 -0
  332. package/src/stateful/index.ts +18 -0
  333. package/src/stateful/provider-event-delivery-failures.ts +80 -0
  334. package/src/stateful/provider-event-pipeline-metrics.ts +95 -0
  335. package/src/stateful/provider-event-pipeline.ts +61 -0
  336. package/src/stateful/provider-events.ts +462 -0
  337. package/src/stateful/session-key.ts +111 -0
  338. package/src/stateful/stateful-provider-adapter-context.ts +59 -0
  339. package/src/stateful/stateful-provider-adapter-metrics.ts +48 -0
  340. package/src/stateful/stateful-provider-adapter.ts +562 -0
  341. package/src/stateful/stateful-provider-observability.ts +261 -0
  342. package/src/stateful/stateful-provider-owner-forwarder.ts +287 -0
  343. package/src/stateful/stateful-provider-runtime-context.ts +92 -0
  344. package/src/stateful/stateful-provider-runtime-executor.ts +96 -0
  345. package/src/stateful/stateful-provider-session-routing.ts +546 -0
  346. package/src/stateful/stateful-provider-session-runtime.ts +403 -0
  347. package/src/stateful-signing.ts +46 -0
  348. package/src/stealth/profiles.ts +202 -231
  349. package/src/stream-evidence.ts +988 -0
  350. package/src/stream.ts +8 -1
  351. package/src/testing/index.ts +10 -1
  352. package/src/testing/run.ts +658 -15
  353. package/src/trace-sanitization.ts +63 -0
  354. package/src/types.ts +788 -174
  355. package/dist/cli/templates/provider/CLAUDE.md.tpl +0 -1
  356. package/src/cli/templates/provider/CLAUDE.md.tpl +0 -1
  357. /package/dist/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
  358. /package/dist/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
  359. /package/dist/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
  360. /package/dist/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
  361. /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
  362. /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
  363. /package/src/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
  364. /package/src/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
  365. /package/src/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
  366. /package/src/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
  367. /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
  368. /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
@@ -0,0 +1,772 @@
1
+ import type TS from "typescript";
2
+
3
+ const ts: typeof import("typescript") = await loadTypeScript();
4
+
5
+ async function loadTypeScript(): Promise<typeof import("typescript")> {
6
+ try {
7
+ return await import("typescript");
8
+ } catch {
9
+ console.error(
10
+ "apifuse migrate-shape requires typescript; install it in the workspace running the CLI (bun add -d typescript)",
11
+ );
12
+ process.exit(1);
13
+ }
14
+ }
15
+
16
+ /**
17
+ * Provider authoring shape migration.
18
+ *
19
+ * `defineProvider` changed in 2.2.0-beta.37 from returning a finished provider
20
+ * to returning a builder, splitting authoring into two phases:
21
+ *
22
+ * const buildProvider = defineProvider(<declaration>);
23
+ * export type ProviderContext = ProviderContextOf<typeof buildProvider>;
24
+ * export default buildProvider({ operations });
25
+ *
26
+ * Source written against the single-phase shape still type-checks against an
27
+ * older pin but default-exports a builder function once the pin moves, so
28
+ * `loadProviderDefinition` rejects it. Bumping the pin without migrating the
29
+ * source therefore breaks the module. This transform performs the source half
30
+ * so the SDK bump fan-out can ship both in one commit.
31
+ *
32
+ * The transform is deliberately conservative: it rewrites only the shapes it
33
+ * can fully account for and reports `skipped` with a reason for anything else,
34
+ * rather than emitting a partial migration a reviewer would have to audit.
35
+ */
36
+
37
+ /** Every source shape this transform recognizes. */
38
+ export type ProviderShapeKind =
39
+ /** `export default defineProvider({ ..., operations })` */
40
+ | "single-phase-default-export"
41
+ /** `const p = defineProvider({ ..., operations }); export default p;` */
42
+ | "single-phase-variable-export"
43
+ /** `const p = defineProvider({ ..., operations }); export default { ...p, deployment };` */
44
+ | "single-phase-variable-spread-export"
45
+ /** Already `const b = defineProvider(...); export default b({ operations })` */
46
+ | "two-phase";
47
+
48
+ export type ProviderShapeMigration =
49
+ | {
50
+ readonly status: "migrated";
51
+ readonly kind: ProviderShapeKind;
52
+ readonly code: string;
53
+ /** Source text the operations map was supplied as, for reporting. */
54
+ readonly operationsExpression: string;
55
+ }
56
+ | {
57
+ readonly status: "unchanged";
58
+ readonly kind: "two-phase";
59
+ readonly code: string;
60
+ }
61
+ | {
62
+ readonly status: "skipped";
63
+ readonly reason: string;
64
+ };
65
+
66
+ const DECLARATION_BUILDER_NAME = "buildProvider";
67
+ const PROVIDER_CONTEXT_TYPE_NAME = "ProviderContext";
68
+ const PROVIDER_CONTEXT_OF_TYPE_NAME = "ProviderContextOf";
69
+ const PROVIDER_SDK_PROVIDER_SUBPATH = "@apifuse/provider-sdk/provider";
70
+
71
+ /**
72
+ * Migrate one provider `index.ts` to the two-phase authoring shape.
73
+ *
74
+ * Returns the rewritten source on success. Callers MUST treat `skipped` as a
75
+ * hard stop for that provider — a skipped provider needs a human, and pairing
76
+ * a pin bump with a skipped migration produces an unloadable module.
77
+ */
78
+ export function migrateProviderShape(
79
+ sourceText: string,
80
+ fileName = "index.ts",
81
+ ): ProviderShapeMigration {
82
+ const source = ts.createSourceFile(
83
+ fileName,
84
+ sourceText,
85
+ ts.ScriptTarget.Latest,
86
+ /* setParentNodes */ true,
87
+ ts.ScriptKind.TS,
88
+ );
89
+
90
+ const syntaxError = firstSyntaxError(source);
91
+ if (syntaxError !== undefined) {
92
+ return { status: "skipped", reason: syntaxError };
93
+ }
94
+
95
+ const calls = collectDefineProviderCalls(source);
96
+ if (calls.length === 0) {
97
+ return {
98
+ status: "skipped",
99
+ reason:
100
+ "No defineProvider(...) call found; this file does not declare a provider.",
101
+ };
102
+ }
103
+ if (calls.length > 1) {
104
+ return {
105
+ status: "skipped",
106
+ reason: `Found ${calls.length} defineProvider(...) calls; the transform rewrites exactly one declaration.`,
107
+ };
108
+ }
109
+
110
+ const call = calls[0];
111
+ if (call === undefined) {
112
+ return { status: "skipped", reason: "Internal: defineProvider call vanished." };
113
+ }
114
+
115
+ const exportAssignment = findDefaultExport(source);
116
+ if (exportAssignment === undefined) {
117
+ return {
118
+ status: "skipped",
119
+ reason:
120
+ "No `export default` found; the provider module must default-export its provider.",
121
+ };
122
+ }
123
+
124
+ const declaration = call.arguments[0];
125
+ if (declaration === undefined || !ts.isObjectLiteralExpression(declaration)) {
126
+ return {
127
+ status: "skipped",
128
+ reason:
129
+ "defineProvider(...) is called with a non-literal argument, so the declaration's operations key cannot be located.",
130
+ };
131
+ }
132
+
133
+ const operationsProperty = findOperationsProperty(declaration);
134
+
135
+ // Already migrated: the declaration carries no operations key and the
136
+ // default export path calls a builder variable rather than defineProvider.
137
+ if (
138
+ operationsProperty === undefined &&
139
+ isAlreadyTwoPhase(source, exportAssignment, call)
140
+ ) {
141
+ return { status: "unchanged", kind: "two-phase", code: sourceText };
142
+ }
143
+
144
+ if (operationsProperty === undefined) {
145
+ return {
146
+ status: "skipped",
147
+ reason:
148
+ "The declaration has no `operations` key and the default export does not call a declaration builder, so the intended shape is ambiguous.",
149
+ };
150
+ }
151
+
152
+ const operationsText = operationsPropertyValueText(operationsProperty, source);
153
+ if (operationsText === undefined) {
154
+ return {
155
+ status: "skipped",
156
+ reason:
157
+ "The `operations` property uses a form the transform cannot relocate (getter, setter, method, spread, or computed name).",
158
+ };
159
+ }
160
+
161
+ const shape = classifyShape(source, call, exportAssignment);
162
+ if (shape.status === "skipped") {
163
+ return shape;
164
+ }
165
+
166
+ const edits: TextEdit[] = [];
167
+ const builderName = pickBuilderName(source);
168
+
169
+ // 1. Remove `operations` from the declaration literal.
170
+ edits.push(...removeOperationsProperty(operationsProperty, declaration, source));
171
+
172
+ // 2. Bind the declaration to `const buildProvider = defineProvider({...})`.
173
+ edits.push(...introduceBuilder(source, call, shape, builderName));
174
+
175
+ // 3. Route the default export through `buildProvider({ operations })`.
176
+ edits.push(
177
+ ...rewriteDefaultExport(source, exportAssignment, shape, builderName, operationsText),
178
+ );
179
+
180
+ // 4. `export type ProviderContext = ProviderContextOf<typeof buildProvider>;`
181
+ // plus the type-only import, when neither is already present.
182
+ edits.push(...ensureProviderContextType(source, call, shape, builderName));
183
+
184
+ const code = applyEdits(sourceText, edits);
185
+
186
+ // Re-parse the output: a transform that emits unparseable source is worse
187
+ // than one that skips, because the pin bump would ship alongside it.
188
+ const verified = ts.createSourceFile(
189
+ fileName,
190
+ code,
191
+ ts.ScriptTarget.Latest,
192
+ true,
193
+ ts.ScriptKind.TS,
194
+ );
195
+ const outputError = firstSyntaxError(verified);
196
+ if (outputError !== undefined) {
197
+ return {
198
+ status: "skipped",
199
+ reason: `Transform produced source that does not parse (${outputError}); refusing to emit a partial migration.`,
200
+ };
201
+ }
202
+
203
+ return {
204
+ status: "migrated",
205
+ kind: shape.kind,
206
+ code,
207
+ operationsExpression: operationsText,
208
+ };
209
+ }
210
+
211
+ type TextEdit = {
212
+ readonly start: number;
213
+ readonly end: number;
214
+ readonly text: string;
215
+ };
216
+
217
+ type ShapeClassification =
218
+ | {
219
+ readonly status: "ok";
220
+ readonly kind: Exclude<ProviderShapeKind, "two-phase">;
221
+ /** Variable the declaration is currently bound to, when it is bound. */
222
+ readonly variableName?: string;
223
+ readonly variableStatement?: TS.VariableStatement;
224
+ /** Extra properties on a `{ ...provider, deployment }` default export. */
225
+ readonly spreadExportExtras?: string;
226
+ }
227
+ | { readonly status: "skipped"; readonly reason: string };
228
+
229
+ function classifyShape(
230
+ source: TS.SourceFile,
231
+ call: TS.CallExpression,
232
+ exportAssignment: TS.ExportAssignment,
233
+ ): ShapeClassification {
234
+ const variableStatement = enclosingVariableStatement(call);
235
+
236
+ if (variableStatement === undefined) {
237
+ // `export default defineProvider({...})`
238
+ if (exportAssignment.expression === call) {
239
+ return { status: "ok", kind: "single-phase-default-export" };
240
+ }
241
+ return {
242
+ status: "skipped",
243
+ reason:
244
+ "defineProvider(...) is neither bound to a variable nor the default-export expression, so the transform cannot place the builder.",
245
+ };
246
+ }
247
+
248
+ const declarations = variableStatement.declarationList.declarations;
249
+ if (declarations.length !== 1) {
250
+ return {
251
+ status: "skipped",
252
+ reason:
253
+ "The defineProvider(...) result is declared alongside other bindings in one statement; split the declaration first.",
254
+ };
255
+ }
256
+ const declaration = declarations[0];
257
+ if (declaration === undefined || !ts.isIdentifier(declaration.name)) {
258
+ return {
259
+ status: "skipped",
260
+ reason: "The defineProvider(...) result is bound to a destructuring pattern.",
261
+ };
262
+ }
263
+ if (declaration.initializer !== call) {
264
+ return {
265
+ status: "skipped",
266
+ reason:
267
+ "defineProvider(...) is nested inside a larger initializer expression the transform cannot rewrite.",
268
+ };
269
+ }
270
+ const variableName = declaration.name.text;
271
+
272
+ const exported = exportAssignment.expression;
273
+
274
+ if (ts.isIdentifier(exported) && exported.text === variableName) {
275
+ return {
276
+ status: "ok",
277
+ kind: "single-phase-variable-export",
278
+ variableName,
279
+ variableStatement,
280
+ };
281
+ }
282
+
283
+ if (ts.isObjectLiteralExpression(exported)) {
284
+ const spreads = exported.properties.filter(ts.isSpreadAssignment);
285
+ const spreadsProvider = spreads.some(
286
+ (property) =>
287
+ ts.isIdentifier(property.expression) &&
288
+ property.expression.text === variableName,
289
+ );
290
+ if (!spreadsProvider) {
291
+ return {
292
+ status: "skipped",
293
+ reason: `The default export is an object literal that does not spread \`${variableName}\`, so the provider value it exports is unclear.`,
294
+ };
295
+ }
296
+ if (spreads.length > 1) {
297
+ return {
298
+ status: "skipped",
299
+ reason:
300
+ "The default export spreads more than one value; the transform cannot tell which carries the provider.",
301
+ };
302
+ }
303
+ const extras = exported.properties.filter(
304
+ (property) => !ts.isSpreadAssignment(property),
305
+ );
306
+ return {
307
+ status: "ok",
308
+ kind: "single-phase-variable-spread-export",
309
+ variableName,
310
+ variableStatement,
311
+ spreadExportExtras: extras
312
+ .map((property) => property.getText(source))
313
+ .join(",\n "),
314
+ };
315
+ }
316
+
317
+ return {
318
+ status: "skipped",
319
+ reason: `The default export is neither \`${variableName}\` nor an object literal spreading it.`,
320
+ };
321
+ }
322
+
323
+ function collectDefineProviderCalls(source: TS.SourceFile): TS.CallExpression[] {
324
+ const calls: TS.CallExpression[] = [];
325
+ const visit = (node: TS.Node): void => {
326
+ if (
327
+ ts.isCallExpression(node) &&
328
+ ts.isIdentifier(node.expression) &&
329
+ node.expression.text === "defineProvider"
330
+ ) {
331
+ calls.push(node);
332
+ }
333
+ ts.forEachChild(node, visit);
334
+ };
335
+ visit(source);
336
+ return calls;
337
+ }
338
+
339
+ function findDefaultExport(source: TS.SourceFile): TS.ExportAssignment | undefined {
340
+ for (const statement of source.statements) {
341
+ if (ts.isExportAssignment(statement) && statement.isExportEquals !== true) {
342
+ return statement;
343
+ }
344
+ }
345
+ return undefined;
346
+ }
347
+
348
+ function defaultExportCallsBuilder(
349
+ exportAssignment: TS.ExportAssignment,
350
+ declarationCall: TS.CallExpression,
351
+ ): boolean {
352
+ const expression = exportAssignment.expression;
353
+ if (!ts.isCallExpression(expression)) return false;
354
+ if (expression === declarationCall) return false;
355
+ return ts.isIdentifier(expression.expression);
356
+ }
357
+
358
+ /**
359
+ * True when the module is already in the two-phase shape: the default export
360
+ * resolves to a builder-call result. Covers the three migrated layouts —
361
+ * `export default buildProvider({...})`, an intermediate
362
+ * `const provider = buildProvider({...}); export default provider;`, and the
363
+ * spread export `export default { ...provider, deployment }` over such a
364
+ * binding. Without the latter two, re-running the transform on its own
365
+ * spread-shape output reports "ambiguous" instead of "unchanged", which
366
+ * breaks idempotency for repeated fan-out runs.
367
+ */
368
+ function isAlreadyTwoPhase(
369
+ source: TS.SourceFile,
370
+ exportAssignment: TS.ExportAssignment,
371
+ declarationCall: TS.CallExpression,
372
+ ): boolean {
373
+ if (defaultExportCallsBuilder(exportAssignment, declarationCall)) return true;
374
+
375
+ const exported = exportAssignment.expression;
376
+ const candidateNames: string[] = [];
377
+ if (ts.isIdentifier(exported)) {
378
+ candidateNames.push(exported.text);
379
+ } else if (ts.isObjectLiteralExpression(exported)) {
380
+ for (const property of exported.properties) {
381
+ if (ts.isSpreadAssignment(property) && ts.isIdentifier(property.expression)) {
382
+ candidateNames.push(property.expression.text);
383
+ }
384
+ }
385
+ }
386
+ if (candidateNames.length === 0) return false;
387
+
388
+ // Does any spread/exported identifier bind a call to an identifier other
389
+ // than defineProvider — i.e. a builder call?
390
+ let found = false;
391
+ const visit = (node: TS.Node): void => {
392
+ if (found) return;
393
+ if (
394
+ ts.isVariableDeclaration(node) &&
395
+ ts.isIdentifier(node.name) &&
396
+ candidateNames.includes(node.name.text) &&
397
+ node.initializer !== undefined &&
398
+ ts.isCallExpression(node.initializer) &&
399
+ node.initializer !== declarationCall &&
400
+ ts.isIdentifier(node.initializer.expression) &&
401
+ node.initializer.expression.text !== "defineProvider"
402
+ ) {
403
+ found = true;
404
+ return;
405
+ }
406
+ ts.forEachChild(node, visit);
407
+ };
408
+ visit(source);
409
+ return found;
410
+ }
411
+
412
+ function findOperationsProperty(
413
+ declaration: TS.ObjectLiteralExpression,
414
+ ): TS.ObjectLiteralElementLike | undefined {
415
+ for (const property of declaration.properties) {
416
+ if (ts.isSpreadAssignment(property)) continue;
417
+ const name = property.name;
418
+ if (name === undefined) continue;
419
+ if (
420
+ (ts.isIdentifier(name) || ts.isStringLiteral(name)) &&
421
+ name.text === "operations"
422
+ ) {
423
+ return property;
424
+ }
425
+ }
426
+ return undefined;
427
+ }
428
+
429
+ /**
430
+ * Source text of the value to hand the builder. Shorthand becomes the bare
431
+ * identifier so `{ operations }` stays idiomatic; a property assignment keeps
432
+ * its initializer verbatim, including a multi-line inline map.
433
+ */
434
+ function operationsPropertyValueText(
435
+ property: TS.ObjectLiteralElementLike,
436
+ source: TS.SourceFile,
437
+ ): string | undefined {
438
+ if (ts.isShorthandPropertyAssignment(property)) {
439
+ return property.name.text;
440
+ }
441
+ if (ts.isPropertyAssignment(property)) {
442
+ return property.initializer.getText(source);
443
+ }
444
+ return undefined;
445
+ }
446
+
447
+ function removeOperationsProperty(
448
+ property: TS.ObjectLiteralElementLike,
449
+ declaration: TS.ObjectLiteralExpression,
450
+ source: TS.SourceFile,
451
+ ): TextEdit[] {
452
+ const properties = declaration.properties;
453
+ const index = properties.indexOf(property);
454
+ const start = property.getFullStart();
455
+ let end = property.getEnd();
456
+
457
+ // Absorb the trailing comma so the remaining literal stays well-formed,
458
+ // whether the key sat mid-list or last.
459
+ const text = source.getFullText();
460
+ let cursor = end;
461
+ while (cursor < text.length && /\s/.test(text.charAt(cursor))) cursor += 1;
462
+ if (text.charAt(cursor) === ",") {
463
+ end = cursor + 1;
464
+ } else if (index > 0) {
465
+ // Last property with no trailing comma: drop the preceding one instead.
466
+ const previous = properties[index - 1];
467
+ if (previous !== undefined) {
468
+ let back = previous.getEnd();
469
+ while (back < text.length && /\s/.test(text.charAt(back))) back += 1;
470
+ if (text.charAt(back) === ",") {
471
+ return [{ start: back, end, text: "" }];
472
+ }
473
+ }
474
+ }
475
+
476
+ return [{ start, end, text: "" }];
477
+ }
478
+
479
+ function introduceBuilder(
480
+ source: TS.SourceFile,
481
+ call: TS.CallExpression,
482
+ shape: Extract<ShapeClassification, { status: "ok" }>,
483
+ builderName: string,
484
+ ): TextEdit[] {
485
+ if (shape.kind === "single-phase-default-export") {
486
+ // `export default defineProvider({...})` becomes a standalone builder
487
+ // declaration; the default export is re-appended separately.
488
+ const exportStatement = call.parent;
489
+ if (!ts.isExportAssignment(exportStatement)) return [];
490
+ return [
491
+ {
492
+ start: exportStatement.getStart(source),
493
+ end: call.getStart(source),
494
+ text: `const ${builderName} = `,
495
+ },
496
+ ];
497
+ }
498
+
499
+ const statement = shape.variableStatement;
500
+ if (statement === undefined || shape.variableName === undefined) return [];
501
+
502
+ // Rename the existing binding to the builder name. The old name is
503
+ // re-introduced for the built provider only in the spread-export shape,
504
+ // which needs an intermediate value to spread.
505
+ const declaration = statement.declarationList.declarations[0];
506
+ if (declaration === undefined || !ts.isIdentifier(declaration.name)) return [];
507
+ return [
508
+ {
509
+ start: declaration.name.getStart(source),
510
+ end: declaration.name.getEnd(),
511
+ text: builderName,
512
+ },
513
+ ];
514
+ }
515
+
516
+ function rewriteDefaultExport(
517
+ source: TS.SourceFile,
518
+ exportAssignment: TS.ExportAssignment,
519
+ shape: Extract<ShapeClassification, { status: "ok" }>,
520
+ builderName: string,
521
+ operationsText: string,
522
+ ): TextEdit[] {
523
+ const operationsArgument =
524
+ operationsText === "operations"
525
+ ? "{ operations }"
526
+ : `{ operations: ${operationsText} }`;
527
+ const call = `${builderName}(${operationsArgument})`;
528
+
529
+ if (shape.kind === "single-phase-default-export") {
530
+ // The builder declaration replaced the `export default` prefix; the
531
+ // export itself is appended after what is now the builder statement.
532
+ return [
533
+ {
534
+ start: exportAssignment.getEnd(),
535
+ end: exportAssignment.getEnd(),
536
+ text: `\n\nexport default ${call};`,
537
+ },
538
+ ];
539
+ }
540
+
541
+ if (shape.kind === "single-phase-variable-export") {
542
+ return [
543
+ {
544
+ start: exportAssignment.expression.getStart(source),
545
+ end: exportAssignment.expression.getEnd(),
546
+ text: call,
547
+ },
548
+ ];
549
+ }
550
+
551
+ // Spread export: re-introduce the provider binding so the extra properties
552
+ // (currently `deployment`) still spread over a built provider.
553
+ const providerName = shape.variableName ?? "provider";
554
+ const extras = shape.spreadExportExtras ?? "";
555
+ const rebuilt =
556
+ extras.length > 0
557
+ ? `{\n ...${providerName},\n ${extras},\n}`
558
+ : `{ ...${providerName} }`;
559
+ return [
560
+ {
561
+ start: exportAssignment.getStart(source),
562
+ end: exportAssignment.getStart(source),
563
+ text: `const ${providerName} = ${call};\n\n`,
564
+ },
565
+ {
566
+ start: exportAssignment.expression.getStart(source),
567
+ end: exportAssignment.expression.getEnd(),
568
+ text: rebuilt,
569
+ },
570
+ ];
571
+ }
572
+
573
+ /**
574
+ * Add `export type ProviderContext = ProviderContextOf<typeof buildProvider>`
575
+ * and the type-only import when absent. Operation handlers reference this
576
+ * type, so a migration that omits it leaves the provider without the context
577
+ * type the two-phase shape exists to provide.
578
+ */
579
+ function ensureProviderContextType(
580
+ source: TS.SourceFile,
581
+ call: TS.CallExpression,
582
+ shape: Extract<ShapeClassification, { status: "ok" }>,
583
+ builderName: string,
584
+ ): TextEdit[] {
585
+ const text = source.getFullText();
586
+ const edits: TextEdit[] = [];
587
+
588
+ const hasContextTypeAlias = source.statements.some(
589
+ (statement) =>
590
+ ts.isTypeAliasDeclaration(statement) &&
591
+ statement.name.text === PROVIDER_CONTEXT_TYPE_NAME,
592
+ );
593
+ // A named import of `ProviderContext` (the deprecated SDK-root context
594
+ // type, imported by legacy sources) occupies the same name: adding the
595
+ // alias alongside it is TS2440. The import must yield to the derived
596
+ // alias — the whole point of the two-phase shape — so drop it and let the
597
+ // alias own the name.
598
+ const conflictingImportSpecifier = findNamedImportSpecifier(
599
+ source,
600
+ PROVIDER_CONTEXT_TYPE_NAME,
601
+ );
602
+
603
+ if (!hasContextTypeAlias) {
604
+ // After the builder statement — which is the variable statement when the
605
+ // declaration was bound, or the rewritten export statement otherwise.
606
+ const anchor =
607
+ shape.variableStatement ??
608
+ (ts.isExportAssignment(call.parent) ? call.parent : undefined);
609
+ if (anchor !== undefined) {
610
+ const insertAt = anchor.getEnd();
611
+ edits.push({
612
+ start: insertAt,
613
+ end: insertAt,
614
+ text: `\n\nexport type ${PROVIDER_CONTEXT_TYPE_NAME} = ${PROVIDER_CONTEXT_OF_TYPE_NAME}<typeof ${builderName}>;`,
615
+ });
616
+ if (conflictingImportSpecifier !== undefined) {
617
+ edits.push(removeImportSpecifier(source, conflictingImportSpecifier));
618
+ }
619
+ }
620
+ }
621
+
622
+ if (text.includes(PROVIDER_CONTEXT_OF_TYPE_NAME)) {
623
+ return edits;
624
+ }
625
+
626
+ const providerImport = findProviderSdkImport(source);
627
+ if (providerImport === undefined) {
628
+ // No named import from the provider subpath to extend; adding a new
629
+ // import line without knowing the module's style is riskier than
630
+ // leaving the type import to `bun run check` feedback.
631
+ return edits;
632
+ }
633
+ const named = providerImport.importClause?.namedBindings;
634
+ if (named === undefined || !ts.isNamedImports(named)) {
635
+ return edits;
636
+ }
637
+ const last = named.elements[named.elements.length - 1];
638
+ if (last === undefined) {
639
+ return edits;
640
+ }
641
+ edits.push({
642
+ start: last.getEnd(),
643
+ end: last.getEnd(),
644
+ text: `, type ${PROVIDER_CONTEXT_OF_TYPE_NAME}`,
645
+ });
646
+ return edits;
647
+ }
648
+
649
+ function findProviderSdkImport(
650
+ source: TS.SourceFile,
651
+ ): TS.ImportDeclaration | undefined {
652
+ for (const statement of source.statements) {
653
+ if (!ts.isImportDeclaration(statement)) continue;
654
+ const moduleSpecifier = statement.moduleSpecifier;
655
+ if (!ts.isStringLiteral(moduleSpecifier)) continue;
656
+ if (moduleSpecifier.text !== PROVIDER_SDK_PROVIDER_SUBPATH) continue;
657
+ const named = statement.importClause?.namedBindings;
658
+ if (named !== undefined && ts.isNamedImports(named)) {
659
+ const importsDefineProvider = named.elements.some(
660
+ (element) => element.name.text === "defineProvider",
661
+ );
662
+ if (importsDefineProvider) return statement;
663
+ }
664
+ }
665
+ return undefined;
666
+ }
667
+
668
+ /** Named import specifier binding `localName` in any import declaration. */
669
+ function findNamedImportSpecifier(
670
+ source: TS.SourceFile,
671
+ localName: string,
672
+ ): TS.ImportSpecifier | undefined {
673
+ for (const statement of source.statements) {
674
+ if (!ts.isImportDeclaration(statement)) continue;
675
+ const named = statement.importClause?.namedBindings;
676
+ if (named === undefined || !ts.isNamedImports(named)) continue;
677
+ for (const element of named.elements) {
678
+ if (element.name.text === localName) return element;
679
+ }
680
+ }
681
+ return undefined;
682
+ }
683
+
684
+ /**
685
+ * Edit removing one specifier from its named-import list, absorbing one
686
+ * neighboring comma so the list stays well-formed. Callers guarantee the
687
+ * list has at least one other specifier (legacy sources always import
688
+ * defineProvider alongside the context type).
689
+ */
690
+ function removeImportSpecifier(
691
+ source: TS.SourceFile,
692
+ specifier: TS.ImportSpecifier,
693
+ ): TextEdit {
694
+ const list = specifier.parent;
695
+ const index = list.elements.indexOf(specifier);
696
+ const text = source.getFullText();
697
+ let start = specifier.getFullStart();
698
+ let end = specifier.getEnd();
699
+ let cursor = end;
700
+ while (cursor < text.length && /\s/.test(text.charAt(cursor))) cursor += 1;
701
+ if (text.charAt(cursor) === ",") {
702
+ end = cursor + 1;
703
+ } else if (index > 0) {
704
+ const previous = list.elements[index - 1];
705
+ if (previous !== undefined) {
706
+ let back = previous.getEnd();
707
+ while (back < text.length && /\s/.test(text.charAt(back))) back += 1;
708
+ if (text.charAt(back) === ",") start = back;
709
+ }
710
+ }
711
+ return { start, end, text: "" };
712
+ }
713
+
714
+ /**
715
+ * `buildProvider` unless the module already binds that name, in which case a
716
+ * numbered suffix keeps the transform from shadowing an existing binding.
717
+ */
718
+ function pickBuilderName(source: TS.SourceFile): string {
719
+ const taken = new Set<string>();
720
+ const visit = (node: TS.Node): void => {
721
+ if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
722
+ taken.add(node.name.text);
723
+ }
724
+ if (ts.isFunctionDeclaration(node) && node.name !== undefined) {
725
+ taken.add(node.name.text);
726
+ }
727
+ if (ts.isImportSpecifier(node)) {
728
+ taken.add(node.name.text);
729
+ }
730
+ ts.forEachChild(node, visit);
731
+ };
732
+ visit(source);
733
+
734
+ if (!taken.has(DECLARATION_BUILDER_NAME)) return DECLARATION_BUILDER_NAME;
735
+ for (let suffix = 2; suffix < 100; suffix += 1) {
736
+ const candidate = `${DECLARATION_BUILDER_NAME}${suffix}`;
737
+ if (!taken.has(candidate)) return candidate;
738
+ }
739
+ return `${DECLARATION_BUILDER_NAME}Migrated`;
740
+ }
741
+
742
+ function enclosingVariableStatement(node: TS.Node): TS.VariableStatement | undefined {
743
+ let current: TS.Node | undefined = node.parent;
744
+ while (current !== undefined) {
745
+ if (ts.isVariableStatement(current)) return current;
746
+ if (ts.isSourceFile(current)) return undefined;
747
+ current = current.parent;
748
+ }
749
+ return undefined;
750
+ }
751
+
752
+ function firstSyntaxError(source: TS.SourceFile): string | undefined {
753
+ const diagnostics = (
754
+ source as TS.SourceFile & { parseDiagnostics?: TS.DiagnosticWithLocation[] }
755
+ ).parseDiagnostics;
756
+ if (diagnostics === undefined || diagnostics.length === 0) return undefined;
757
+ const first = diagnostics[0];
758
+ if (first === undefined) return undefined;
759
+ const message = ts.flattenDiagnosticMessageText(first.messageText, " ");
760
+ const { line } = source.getLineAndCharacterOfPosition(first.start);
761
+ return `${message} (line ${line + 1})`;
762
+ }
763
+
764
+ /** Apply edits back-to-front so earlier offsets stay valid. */
765
+ function applyEdits(text: string, edits: readonly TextEdit[]): string {
766
+ const ordered = [...edits].sort((a, b) => b.start - a.start || b.end - a.end);
767
+ let output = text;
768
+ for (const edit of ordered) {
769
+ output = output.slice(0, edit.start) + edit.text + output.slice(edit.end);
770
+ }
771
+ return output;
772
+ }