@ai-agent-forge/agent-forge 0.88.0 → 0.88.1

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 (360) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/bundled-plugins/agent-loop-policy/agent-forge.json +19 -0
  3. package/bundled-plugins/agent-loop-policy/dist/entry.d.ts +28 -0
  4. package/bundled-plugins/agent-loop-policy/dist/entry.d.ts.map +1 -0
  5. package/bundled-plugins/agent-loop-policy/dist/entry.js +69 -0
  6. package/bundled-plugins/agent-loop-policy/dist/entry.js.map +1 -0
  7. package/bundled-plugins/agent-loop-policy/dist/loop-guard.d.ts +199 -0
  8. package/bundled-plugins/agent-loop-policy/dist/loop-guard.d.ts.map +1 -0
  9. package/bundled-plugins/agent-loop-policy/dist/loop-guard.js +208 -0
  10. package/bundled-plugins/agent-loop-policy/dist/loop-guard.js.map +1 -0
  11. package/bundled-plugins/agent-loop-policy/dist/run-loop-strategy.d.ts +17 -0
  12. package/bundled-plugins/agent-loop-policy/dist/run-loop-strategy.d.ts.map +1 -0
  13. package/bundled-plugins/agent-loop-policy/dist/run-loop-strategy.js +18 -0
  14. package/bundled-plugins/agent-loop-policy/dist/run-loop-strategy.js.map +1 -0
  15. package/bundled-plugins/agent-loop-policy/plugin.json +7 -0
  16. package/bundled-plugins/coding-tools/agent-forge.json +19 -0
  17. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/bash.d.ts +5 -44
  18. package/bundled-plugins/coding-tools/dist/bash.d.ts.map +1 -0
  19. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/bash.js +15 -119
  20. package/bundled-plugins/coding-tools/dist/bash.js.map +1 -0
  21. package/bundled-plugins/coding-tools/dist/capability.d.ts +25 -0
  22. package/bundled-plugins/coding-tools/dist/capability.d.ts.map +1 -0
  23. package/bundled-plugins/coding-tools/dist/capability.js +98 -0
  24. package/bundled-plugins/coding-tools/dist/capability.js.map +1 -0
  25. package/bundled-plugins/coding-tools/dist/config.d.ts +8 -0
  26. package/bundled-plugins/coding-tools/dist/config.d.ts.map +1 -0
  27. package/bundled-plugins/coding-tools/dist/config.js +8 -0
  28. package/bundled-plugins/coding-tools/dist/config.js.map +1 -0
  29. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/edit.d.ts +3 -3
  30. package/bundled-plugins/coding-tools/dist/edit.d.ts.map +1 -0
  31. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/edit.js +12 -10
  32. package/bundled-plugins/coding-tools/dist/edit.js.map +1 -0
  33. package/bundled-plugins/coding-tools/dist/entry.d.ts +14 -0
  34. package/bundled-plugins/coding-tools/dist/entry.d.ts.map +1 -0
  35. package/bundled-plugins/coding-tools/dist/entry.js +23 -0
  36. package/bundled-plugins/coding-tools/dist/entry.js.map +1 -0
  37. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/find.d.ts +4 -4
  38. package/bundled-plugins/coding-tools/dist/find.d.ts.map +1 -0
  39. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/find.js +10 -8
  40. package/bundled-plugins/coding-tools/dist/find.js.map +1 -0
  41. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/grep.d.ts +3 -3
  42. package/bundled-plugins/coding-tools/dist/grep.d.ts.map +1 -0
  43. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/grep.js +10 -8
  44. package/bundled-plugins/coding-tools/dist/grep.js.map +1 -0
  45. package/bundled-plugins/coding-tools/dist/index.d.ts +17 -0
  46. package/bundled-plugins/coding-tools/dist/index.d.ts.map +1 -0
  47. package/bundled-plugins/coding-tools/dist/index.js +17 -0
  48. package/bundled-plugins/coding-tools/dist/index.js.map +1 -0
  49. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/ls.d.ts +3 -3
  50. package/bundled-plugins/coding-tools/dist/ls.d.ts.map +1 -0
  51. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/ls.js +8 -6
  52. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/ls.js.map +1 -1
  53. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/powershell.d.ts +2 -1
  54. package/bundled-plugins/coding-tools/dist/powershell.d.ts.map +1 -0
  55. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/powershell.js +6 -3
  56. package/bundled-plugins/coding-tools/dist/powershell.js.map +1 -0
  57. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/read.d.ts +3 -3
  58. package/bundled-plugins/coding-tools/dist/read.d.ts.map +1 -0
  59. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/read.js +15 -13
  60. package/bundled-plugins/coding-tools/dist/read.js.map +1 -0
  61. package/bundled-plugins/coding-tools/dist/types.d.ts +74 -0
  62. package/bundled-plugins/coding-tools/dist/types.d.ts.map +1 -0
  63. package/bundled-plugins/coding-tools/dist/types.js +28 -0
  64. package/bundled-plugins/coding-tools/dist/types.js.map +1 -0
  65. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/write.d.ts +2 -2
  66. package/bundled-plugins/coding-tools/dist/write.d.ts.map +1 -0
  67. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/write.js +11 -9
  68. package/bundled-plugins/coding-tools/dist/write.js.map +1 -0
  69. package/bundled-plugins/coding-tools/plugin.json +10 -0
  70. package/bundled-plugins/compaction-policy/agent-forge.json +19 -0
  71. package/bundled-plugins/compaction-policy/dist/branch-summary-policy.d.ts +6 -0
  72. package/bundled-plugins/compaction-policy/dist/branch-summary-policy.d.ts.map +1 -0
  73. package/bundled-plugins/compaction-policy/dist/branch-summary-policy.js +19 -0
  74. package/bundled-plugins/compaction-policy/dist/branch-summary-policy.js.map +1 -0
  75. package/bundled-plugins/compaction-policy/dist/compaction-policy.d.ts +6 -0
  76. package/bundled-plugins/compaction-policy/dist/compaction-policy.d.ts.map +1 -0
  77. package/bundled-plugins/compaction-policy/dist/compaction-policy.js +38 -0
  78. package/bundled-plugins/compaction-policy/dist/compaction-policy.js.map +1 -0
  79. package/bundled-plugins/compaction-policy/dist/entry.d.ts +13 -0
  80. package/bundled-plugins/compaction-policy/dist/entry.d.ts.map +1 -0
  81. package/bundled-plugins/compaction-policy/dist/entry.js +23 -0
  82. package/bundled-plugins/compaction-policy/dist/entry.js.map +1 -0
  83. package/bundled-plugins/compaction-policy/plugin.json +10 -0
  84. package/bundled-plugins/mcp-http/dist/index.d.ts +8 -0
  85. package/bundled-plugins/mcp-http/dist/index.d.ts.map +1 -0
  86. package/bundled-plugins/mcp-http/dist/index.js +8 -0
  87. package/bundled-plugins/mcp-http/dist/index.js.map +1 -0
  88. package/bundled-plugins/mcp-http/dist/mcp-http.d.ts.map +1 -0
  89. package/{dist/plugins → bundled-plugins/mcp-http/dist}/mcp-http.js +1 -1
  90. package/bundled-plugins/mcp-http/dist/mcp-http.js.map +1 -0
  91. package/bundled-plugins/overflow-policy/agent-forge.json +19 -0
  92. package/bundled-plugins/overflow-policy/dist/entry.d.ts +16 -0
  93. package/bundled-plugins/overflow-policy/dist/entry.d.ts.map +1 -0
  94. package/bundled-plugins/overflow-policy/dist/entry.js +35 -0
  95. package/bundled-plugins/overflow-policy/dist/entry.js.map +1 -0
  96. package/bundled-plugins/overflow-policy/plugin.json +10 -0
  97. package/bundled-plugins/provider-failover/agent-forge.json +19 -0
  98. package/bundled-plugins/provider-failover/dist/entry.d.ts +8 -0
  99. package/bundled-plugins/provider-failover/dist/entry.d.ts.map +1 -0
  100. package/bundled-plugins/provider-failover/dist/entry.js +8 -0
  101. package/bundled-plugins/provider-failover/dist/entry.js.map +1 -0
  102. package/bundled-plugins/provider-failover/dist/provider-failover.d.ts +122 -0
  103. package/bundled-plugins/provider-failover/dist/provider-failover.d.ts.map +1 -0
  104. package/{dist/core/extensions → bundled-plugins/provider-failover/dist}/provider-failover.js +143 -56
  105. package/bundled-plugins/provider-failover/dist/provider-failover.js.map +1 -0
  106. package/bundled-plugins/provider-failover/plugin.json +7 -0
  107. package/bundled-plugins/retry-policy/agent-forge.json +19 -0
  108. package/bundled-plugins/retry-policy/dist/entry.d.ts +16 -0
  109. package/bundled-plugins/retry-policy/dist/entry.d.ts.map +1 -0
  110. package/bundled-plugins/retry-policy/dist/entry.js +34 -0
  111. package/bundled-plugins/retry-policy/dist/entry.js.map +1 -0
  112. package/bundled-plugins/retry-policy/plugin.json +10 -0
  113. package/dist/bundle/.build-manifest.json +61 -117
  114. package/dist/bundle/chunks/{anthropic-messages-ALDZBUKI.js → anthropic-messages-PLAKXR73.js} +1 -1
  115. package/dist/bundle/chunks/{azure-openai-responses-A2WJWZFB.js → azure-openai-responses-OUWQ2AZD.js} +1 -1
  116. package/dist/bundle/chunks/{chunk-CIX3FSBK.js → chunk-A3JYRWB6.js} +1 -1
  117. package/dist/bundle/chunks/{chunk-SQFG22WN.js → chunk-AC2FIS4G.js} +1 -1
  118. package/dist/bundle/chunks/chunk-AQLNTW2B.js +664 -0
  119. package/dist/bundle/chunks/chunk-D3ARGZFR.js +13 -0
  120. package/dist/bundle/chunks/{chunk-YJCQVXW5.js → chunk-HTEVUY7F.js} +1 -1
  121. package/dist/bundle/chunks/{chunk-Y7HXTASS.js → chunk-HV64ASMT.js} +1 -1
  122. package/dist/bundle/chunks/chunk-LZOEQITZ.js +855 -0
  123. package/dist/bundle/chunks/{chunk-7ZY7IXZD.js → chunk-TRDNDS6A.js} +1 -1
  124. package/dist/bundle/chunks/chunk-Z72JWUZ4.js +4 -0
  125. package/dist/bundle/chunks/{google-generative-ai-NIB4WONV.js → google-generative-ai-DLII6DAT.js} +1 -1
  126. package/dist/bundle/chunks/{google-vertex-DCPYUEUO.js → google-vertex-G7BZL7GM.js} +1 -1
  127. package/dist/bundle/chunks/image-resize-worker.js +2 -2
  128. package/dist/bundle/chunks/{mistral-conversations-OC6LA5XL.js → mistral-conversations-JXUK24ID.js} +1 -1
  129. package/dist/bundle/chunks/{openai-codex-responses-IO2X4Y7L.js → openai-codex-responses-5GSGFIPG.js} +1 -1
  130. package/dist/bundle/chunks/{openai-completions-XYQQHETU.js → openai-completions-EI2I6DTG.js} +1 -1
  131. package/dist/bundle/chunks/{openai-responses-DLIRN3CI.js → openai-responses-AUJQ3NWT.js} +1 -1
  132. package/dist/bundle/chunks/{pi-messages-E6RRYBO7.js → pi-messages-PWU2VJMR.js} +1 -1
  133. package/dist/bundle/chunks/virtual-modules-WF6WRHP7.js +5 -0
  134. package/dist/bundle/cli.js +1 -1
  135. package/dist/bundle/client.js +1 -1
  136. package/dist/bundle/index.js +3 -3
  137. package/dist/bundle/rpc-entry.js +1 -1
  138. package/dist/capabilities/builtin.d.ts +1 -1
  139. package/dist/capabilities/builtin.d.ts.map +1 -1
  140. package/dist/capabilities/builtin.js +5 -0
  141. package/dist/capabilities/builtin.js.map +1 -1
  142. package/dist/cli/plugin-command.d.ts.map +1 -1
  143. package/dist/cli/plugin-command.js +17 -1
  144. package/dist/cli/plugin-command.js.map +1 -1
  145. package/dist/config.d.ts +2 -3
  146. package/dist/config.d.ts.map +1 -1
  147. package/dist/config.js +2 -4
  148. package/dist/config.js.map +1 -1
  149. package/dist/core/agent-session-bash.d.ts +1 -1
  150. package/dist/core/agent-session-bash.d.ts.map +1 -1
  151. package/dist/core/agent-session-bash.js +1 -1
  152. package/dist/core/agent-session-bash.js.map +1 -1
  153. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  154. package/dist/core/agent-session-compaction.js +14 -1
  155. package/dist/core/agent-session-compaction.js.map +1 -1
  156. package/dist/core/agent-session-internal.d.ts +1 -1
  157. package/dist/core/agent-session-internal.d.ts.map +1 -1
  158. package/dist/core/agent-session-internal.js.map +1 -1
  159. package/dist/core/agent-session-loop.d.ts +4 -3
  160. package/dist/core/agent-session-loop.d.ts.map +1 -1
  161. package/dist/core/agent-session-loop.js +9 -6
  162. package/dist/core/agent-session-loop.js.map +1 -1
  163. package/dist/core/agent-session-retry.d.ts +1 -1
  164. package/dist/core/agent-session-retry.d.ts.map +1 -1
  165. package/dist/core/agent-session-retry.js +32 -3
  166. package/dist/core/agent-session-retry.js.map +1 -1
  167. package/dist/core/agent-session-services.d.ts.map +1 -1
  168. package/dist/core/agent-session-services.js +30 -9
  169. package/dist/core/agent-session-services.js.map +1 -1
  170. package/dist/core/agent-session-tools.d.ts.map +1 -1
  171. package/dist/core/agent-session-tools.js +5 -1
  172. package/dist/core/agent-session-tools.js.map +1 -1
  173. package/dist/core/agent-session.d.ts +12 -13
  174. package/dist/core/agent-session.d.ts.map +1 -1
  175. package/dist/core/agent-session.js +56 -34
  176. package/dist/core/agent-session.js.map +1 -1
  177. package/dist/core/bash-executor.d.ts +1 -1
  178. package/dist/core/bash-executor.d.ts.map +1 -1
  179. package/dist/core/bash-executor.js.map +1 -1
  180. package/dist/core/extensions/bootstrap-agent-loop.d.ts +23 -151
  181. package/dist/core/extensions/bootstrap-agent-loop.d.ts.map +1 -1
  182. package/dist/core/extensions/bootstrap-agent-loop.js +28 -290
  183. package/dist/core/extensions/bootstrap-agent-loop.js.map +1 -1
  184. package/dist/core/extensions/capability-runtime-types.d.ts +5 -3
  185. package/dist/core/extensions/capability-runtime-types.d.ts.map +1 -1
  186. package/dist/core/extensions/capability-runtime-types.js.map +1 -1
  187. package/dist/core/extensions/capability-runtime.d.ts.map +1 -1
  188. package/dist/core/extensions/capability-runtime.js +42 -6
  189. package/dist/core/extensions/capability-runtime.js.map +1 -1
  190. package/dist/core/extensions/index.d.ts +12 -5
  191. package/dist/core/extensions/index.d.ts.map +1 -1
  192. package/dist/core/extensions/index.js +12 -5
  193. package/dist/core/extensions/index.js.map +1 -1
  194. package/dist/core/extensions/virtual-modules.d.ts.map +1 -1
  195. package/dist/core/extensions/virtual-modules.js +65 -0
  196. package/dist/core/extensions/virtual-modules.js.map +1 -1
  197. package/dist/core/facade/coding-agent-facade.d.ts +1 -1
  198. package/dist/core/facade/coding-agent-facade.d.ts.map +1 -1
  199. package/dist/core/facade/coding-agent-facade.js.map +1 -1
  200. package/dist/core/i18n/locales/zh-cn/core-contract-core.d.ts +1 -1
  201. package/dist/core/i18n/locales/zh-cn/core-contract-core.d.ts.map +1 -1
  202. package/dist/core/i18n/locales/zh-cn/core-contract-core.js +1 -1
  203. package/dist/core/i18n/locales/zh-cn/core-contract-core.js.map +1 -1
  204. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.d.ts.map +1 -1
  205. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.js +2 -4
  206. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.js.map +1 -1
  207. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts.map +1 -1
  208. package/dist/core/i18n/locales/zh-cn/core-errors.js +3 -1
  209. package/dist/core/i18n/locales/zh-cn/core-errors.js.map +1 -1
  210. package/dist/core/sdk.d.ts +10 -3
  211. package/dist/core/sdk.d.ts.map +1 -1
  212. package/dist/core/sdk.js +263 -77
  213. package/dist/core/sdk.js.map +1 -1
  214. package/dist/core/tools/bash-operations.d.ts +41 -0
  215. package/dist/core/tools/bash-operations.d.ts.map +1 -0
  216. package/dist/core/tools/bash-operations.js +113 -0
  217. package/dist/core/tools/bash-operations.js.map +1 -0
  218. package/dist/core/tools/index.d.ts +12 -36
  219. package/dist/core/tools/index.d.ts.map +1 -1
  220. package/dist/core/tools/index.js +1 -117
  221. package/dist/core/tools/index.js.map +1 -1
  222. package/dist/core/tools/readme-path.d.ts +3 -0
  223. package/dist/core/tools/readme-path.d.ts.map +1 -0
  224. package/dist/core/tools/readme-path.js +15 -0
  225. package/dist/core/tools/readme-path.js.map +1 -0
  226. package/dist/index.d.ts +3 -19
  227. package/dist/index.d.ts.map +1 -1
  228. package/dist/index.js +6 -39
  229. package/dist/index.js.map +1 -1
  230. package/dist/modes/interactive/components/tool-execution.d.ts +0 -1
  231. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  232. package/dist/modes/interactive/components/tool-execution.js +9 -25
  233. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  234. package/dist/plugins/ecosystem/cli.d.ts.map +1 -1
  235. package/dist/plugins/ecosystem/cli.js +14 -2
  236. package/dist/plugins/ecosystem/cli.js.map +1 -1
  237. package/dist/plugins/ecosystem/node-npm-registry-source.d.ts +7 -2
  238. package/dist/plugins/ecosystem/node-npm-registry-source.d.ts.map +1 -1
  239. package/dist/plugins/ecosystem/node-npm-registry-source.js +64 -9
  240. package/dist/plugins/ecosystem/node-npm-registry-source.js.map +1 -1
  241. package/dist/plugins/ecosystem/node-plugin-acquisition-host.d.ts.map +1 -1
  242. package/dist/plugins/ecosystem/node-plugin-acquisition-host.js +6 -0
  243. package/dist/plugins/ecosystem/node-plugin-acquisition-host.js.map +1 -1
  244. package/dist/profiles/builtin-suites.d.ts +5 -1
  245. package/dist/profiles/builtin-suites.d.ts.map +1 -1
  246. package/dist/profiles/builtin-suites.js +6 -1
  247. package/dist/profiles/builtin-suites.js.map +1 -1
  248. package/examples/extensions/bash-spawn-hook/index.ts +7 -2
  249. package/examples/extensions/built-in-tool-renderer/index.ts +4 -2
  250. package/examples/extensions/minimal-mode/index.ts +2 -2
  251. package/examples/extensions/truncated-tool/index.ts +1 -1
  252. package/examples/extensions/with-deps/package-lock.json +2 -2
  253. package/examples/extensions/with-deps/package.json +1 -1
  254. package/examples/extensions/with-deps/plugin.json +1 -1
  255. package/package.json +3 -2
  256. package/dist/bundle/chunks/chunk-6ZKDNZHA.js +0 -145
  257. package/dist/bundle/chunks/chunk-HLJEVRWP.js +0 -13
  258. package/dist/bundle/chunks/chunk-YGHQME4V.js +0 -1456
  259. package/dist/bundle/chunks/virtual-modules-KZ5DRH7Q.js +0 -2
  260. package/dist/core/extensions/bootstrap-branch-summary-policy.d.ts +0 -7
  261. package/dist/core/extensions/bootstrap-branch-summary-policy.d.ts.map +0 -1
  262. package/dist/core/extensions/bootstrap-branch-summary-policy.js +0 -28
  263. package/dist/core/extensions/bootstrap-branch-summary-policy.js.map +0 -1
  264. package/dist/core/extensions/bootstrap-compaction-policy.d.ts +0 -7
  265. package/dist/core/extensions/bootstrap-compaction-policy.d.ts.map +0 -1
  266. package/dist/core/extensions/bootstrap-compaction-policy.js +0 -48
  267. package/dist/core/extensions/bootstrap-compaction-policy.js.map +0 -1
  268. package/dist/core/extensions/bootstrap-overflow-policy.d.ts +0 -7
  269. package/dist/core/extensions/bootstrap-overflow-policy.d.ts.map +0 -1
  270. package/dist/core/extensions/bootstrap-overflow-policy.js +0 -30
  271. package/dist/core/extensions/bootstrap-overflow-policy.js.map +0 -1
  272. package/dist/core/extensions/bootstrap-retry-policy.d.ts +0 -7
  273. package/dist/core/extensions/bootstrap-retry-policy.d.ts.map +0 -1
  274. package/dist/core/extensions/bootstrap-retry-policy.js +0 -29
  275. package/dist/core/extensions/bootstrap-retry-policy.js.map +0 -1
  276. package/dist/core/extensions/bootstrap-tools.d.ts +0 -20
  277. package/dist/core/extensions/bootstrap-tools.d.ts.map +0 -1
  278. package/dist/core/extensions/bootstrap-tools.js +0 -36
  279. package/dist/core/extensions/bootstrap-tools.js.map +0 -1
  280. package/dist/core/extensions/provider-failover.d.ts +0 -110
  281. package/dist/core/extensions/provider-failover.d.ts.map +0 -1
  282. package/dist/core/extensions/provider-failover.js.map +0 -1
  283. package/dist/core/tools/bash.d.ts.map +0 -1
  284. package/dist/core/tools/bash.js.map +0 -1
  285. package/dist/core/tools/edit.d.ts.map +0 -1
  286. package/dist/core/tools/edit.js.map +0 -1
  287. package/dist/core/tools/find.d.ts.map +0 -1
  288. package/dist/core/tools/find.js.map +0 -1
  289. package/dist/core/tools/grep.d.ts.map +0 -1
  290. package/dist/core/tools/grep.js.map +0 -1
  291. package/dist/core/tools/ls.d.ts.map +0 -1
  292. package/dist/core/tools/powershell.d.ts.map +0 -1
  293. package/dist/core/tools/powershell.js.map +0 -1
  294. package/dist/core/tools/read.d.ts.map +0 -1
  295. package/dist/core/tools/read.js.map +0 -1
  296. package/dist/core/tools/write.d.ts.map +0 -1
  297. package/dist/core/tools/write.js.map +0 -1
  298. package/dist/plugins/mcp-http.d.ts.map +0 -1
  299. package/dist/plugins/mcp-http.js.map +0 -1
  300. package/dist/profile/child-facade.d.ts +0 -44
  301. package/dist/profile/child-facade.d.ts.map +0 -1
  302. package/dist/profile/child-facade.js +0 -56
  303. package/dist/profile/child-facade.js.map +0 -1
  304. package/dist/profile/dependency-wiring.d.ts +0 -48
  305. package/dist/profile/dependency-wiring.d.ts.map +0 -1
  306. package/dist/profile/dependency-wiring.js +0 -56
  307. package/dist/profile/dependency-wiring.js.map +0 -1
  308. package/dist/profile/domain-recovery.d.ts +0 -60
  309. package/dist/profile/domain-recovery.d.ts.map +0 -1
  310. package/dist/profile/domain-recovery.js +0 -94
  311. package/dist/profile/domain-recovery.js.map +0 -1
  312. package/dist/profile/first-roles.d.ts +0 -30
  313. package/dist/profile/first-roles.d.ts.map +0 -1
  314. package/dist/profile/first-roles.js +0 -83
  315. package/dist/profile/first-roles.js.map +0 -1
  316. package/dist/profile/goal-plugin.d.ts +0 -38
  317. package/dist/profile/goal-plugin.d.ts.map +0 -1
  318. package/dist/profile/goal-plugin.js +0 -132
  319. package/dist/profile/goal-plugin.js.map +0 -1
  320. package/dist/profile/plan-plugin.d.ts +0 -44
  321. package/dist/profile/plan-plugin.d.ts.map +0 -1
  322. package/dist/profile/plan-plugin.js +0 -157
  323. package/dist/profile/plan-plugin.js.map +0 -1
  324. package/dist/profile/policy-manifest.d.ts +0 -53
  325. package/dist/profile/policy-manifest.d.ts.map +0 -1
  326. package/dist/profile/policy-manifest.js +0 -53
  327. package/dist/profile/policy-manifest.js.map +0 -1
  328. package/dist/profile/role-assembly.d.ts +0 -47
  329. package/dist/profile/role-assembly.d.ts.map +0 -1
  330. package/dist/profile/role-assembly.js +0 -31
  331. package/dist/profile/role-assembly.js.map +0 -1
  332. package/dist/profile/role-catalog.d.ts +0 -43
  333. package/dist/profile/role-catalog.d.ts.map +0 -1
  334. package/dist/profile/role-catalog.js +0 -132
  335. package/dist/profile/role-catalog.js.map +0 -1
  336. package/dist/profile/role-orchestrator.d.ts +0 -123
  337. package/dist/profile/role-orchestrator.d.ts.map +0 -1
  338. package/dist/profile/role-orchestrator.js +0 -195
  339. package/dist/profile/role-orchestrator.js.map +0 -1
  340. package/dist/profile/role-runner.d.ts +0 -99
  341. package/dist/profile/role-runner.d.ts.map +0 -1
  342. package/dist/profile/role-runner.js +0 -79
  343. package/dist/profile/role-runner.js.map +0 -1
  344. package/dist/profile/root-facade.d.ts +0 -36
  345. package/dist/profile/root-facade.d.ts.map +0 -1
  346. package/dist/profile/root-facade.js +0 -49
  347. package/dist/profile/root-facade.js.map +0 -1
  348. package/dist/profile/skill-discovery-wiring.d.ts +0 -58
  349. package/dist/profile/skill-discovery-wiring.d.ts.map +0 -1
  350. package/dist/profile/skill-discovery-wiring.js +0 -80
  351. package/dist/profile/skill-discovery-wiring.js.map +0 -1
  352. package/dist/profile/state-store.d.ts +0 -62
  353. package/dist/profile/state-store.d.ts.map +0 -1
  354. package/dist/profile/state-store.js +0 -144
  355. package/dist/profile/state-store.js.map +0 -1
  356. package/dist/profile/todo-plugin.d.ts +0 -37
  357. package/dist/profile/todo-plugin.d.ts.map +0 -1
  358. package/dist/profile/todo-plugin.js +0 -137
  359. package/dist/profile/todo-plugin.js.map +0 -1
  360. /package/{dist/plugins → bundled-plugins/mcp-http/dist}/mcp-http.d.ts +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"node-npm-registry-source.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-npm-registry-source.ts"],"names":[],"mappings":"AAsBA,MAAM,MAAM,gCAAgC,GACzC,WAAW,GACX,uBAAuB,GACvB,gBAAgB,GAChB,mBAAmB,GACnB,kBAAkB,GAClB,oBAAoB,GACpB,mBAAmB,GACnB,mBAAmB,GACnB,uBAAuB,CAAC;AAE3B,qBAAa,4BAA6B,SAAQ,KAAK;IACtD,QAAQ,CAAC,IAAI,EAAE,gCAAgC,CAAC;IAEhD,YAAY,IAAI,EAAE,gCAAgC,EAAE,OAAO,EAAE,MAAM,EAIlE;CACD;AAED,4FAA4F;AAC5F,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,SAAS,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC;IACvC,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,8BAA8B;IAC9C,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,2CAA2C;IAC3C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACzC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,iFAAiF;IACjF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,iBAAiB,EAAE,CAAC,KAAK,EAAE;QACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;KAC9B,KAAK,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC1C,QAAQ,CAAC,YAAY,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CAC/G;AAED,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,CAgBhE;AAgBD;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAmBzG;AAsKD,6FAA6F;AAC7F,wBAAgB,6BAA6B,CAAC,OAAO,GAAE,8BAAmC,GAAG,uBAAuB,CA8InH","sourcesContent":["import { t } from \"../../core/i18n/index.ts\";\nimport { comparePluginVersionsV1 } from \"./catalog.ts\";\n\n/**\n * Minimal npm registry (packument) source for plugin package acquisition\n * (design `插件独立分发与启动装配设计.md` §4.2). It is a two-step protocol:\n * resolve the packument to pick one version, then fetch the tarball. It does\n * not implement `PluginRegistrySourceV1.list()`; the signed registry sources\n * keep serving private deployments unchanged.\n */\n\nconst DEFAULT_NPM_REGISTRY_V1 = \"https://registry.npmjs.org\";\nconst DEFAULT_TIMEOUT_MS_V1 = 15_000;\nconst MAX_TIMEOUT_MS_V1 = 120_000;\nconst DEFAULT_MAX_RESPONSE_BYTES_V1 = 8 * 1024 * 1024;\nconst MAX_RESPONSE_BYTES_V1 = 16 * 1024 * 1024;\nconst DEFAULT_MAX_TARBALL_BYTES_V1 = 128 * 1024 * 1024;\nconst MAX_TARBALL_BYTES_V1 = 512 * 1024 * 1024;\nconst DEFAULT_REDIRECTS_V1 = 3;\nconst MAX_REDIRECTS_V1 = 5;\nconst REDIRECT_STATUS = new Set([301, 302, 303, 307, 308]);\n\nexport type NodeNpmRegistrySourceErrorCodeV1 =\n\t| \"cancelled\"\n\t| \"invalid_configuration\"\n\t| \"request_failed\"\n\t| \"request_timed_out\"\n\t| \"invalid_response\"\n\t| \"response_too_large\"\n\t| \"package_not_found\"\n\t| \"version_not_found\"\n\t| \"integrity_unsupported\";\n\nexport class NodeNpmRegistrySourceErrorV1 extends Error {\n\treadonly code: NodeNpmRegistrySourceErrorCodeV1;\n\n\tconstructor(code: NodeNpmRegistrySourceErrorCodeV1, message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"NodeNpmRegistrySourceErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\n/** SRI integrity as hex plus its algorithm, aligned with the install host digest format. */\nexport interface NodeNpmIntegrityV1 {\n\treadonly algorithm: \"sha256\" | \"sha512\";\n\treadonly hex: string;\n}\n\nexport interface NodeNpmPackageResolutionV1 {\n\treadonly version: string;\n\treadonly tarballUrl: string;\n\treadonly integrity: NodeNpmIntegrityV1;\n\t/** Raw `dist` fields of the selected version. */\n\treadonly distInfo: Readonly<Record<string, unknown>>;\n}\n\nexport interface NodeNpmRegistrySourceOptionsV1 {\n\t/** Bare http(s) registry origin; defaults to the npm public registry. */\n\treadonly registry?: string;\n\t/** Bearer token for private registries. */\n\treadonly token?: string;\n\t/** Real fetch or a deterministic test replacement. */\n\treadonly fetch?: typeof globalThis.fetch;\n\treadonly requestTimeoutMs?: number;\n\treadonly maxResponseBytes?: number;\n\treadonly maxTarballBytes?: number;\n\treadonly maxRedirects?: number;\n\treadonly userAgent?: string;\n}\n\nexport interface NodeNpmRegistrySourceV1 {\n\treadonly version: 1;\n\t/** Sanitized bare registry origin (no credentials, path, query, or fragment). */\n\treadonly registry: string;\n\treadonly resolveNpmPackage: (input: {\n\t\treadonly name: string;\n\t\treadonly range?: string;\n\t\treadonly signal?: AbortSignal;\n\t}) => Promise<NodeNpmPackageResolutionV1>;\n\treadonly fetchTarball: (input: { readonly url: string; readonly signal?: AbortSignal }) => Promise<Uint8Array>;\n}\n\n/** Convert an npm SRI string (`sha512-<base64>`, `sha256-<base64>`) to hex form. */\nexport function sriToIntegrityV1(sri: string): NodeNpmIntegrityV1 {\n\tconst match = /^(sha512|sha256)-([A-Za-z0-9+/]+={0,2})$/u.exec(sri.trim());\n\tif (match === null)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"integrity_unsupported\", t(\"npm integrity algorithm is unsupported\"));\n\tconst algorithm = match[1] as \"sha512\" | \"sha256\";\n\tlet raw: Buffer;\n\ttry {\n\t\traw = Buffer.from(match[2]!, \"base64\");\n\t} catch {\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"integrity_unsupported\", t(\"npm integrity encoding is invalid\"));\n\t}\n\tif ((algorithm === \"sha256\" && raw.byteLength !== 32) || (algorithm === \"sha512\" && raw.byteLength !== 64))\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"integrity_unsupported\", t(\"npm integrity length is invalid\"));\n\tconst hex = raw.toString(\"hex\").toLowerCase();\n\tif (hex.length === 0) throw new NodeNpmRegistrySourceErrorV1(\"integrity_unsupported\", t(\"npm integrity is invalid\"));\n\treturn { algorithm, hex };\n}\n\nfunction parseVersionTriple(value: string): readonly [number, number, number] | undefined {\n\tconst match = /^(\\d+)\\.(\\d+)\\.(\\d+)/u.exec(value.replace(/^[vV]/u, \"\"));\n\tif (match === null) return undefined;\n\tconst major = Number.parseInt(match[1]!, 10);\n\tconst minor = Number.parseInt(match[2]!, 10);\n\tconst patch = Number.parseInt(match[3]!, 10);\n\tif (!Number.isSafeInteger(major) || !Number.isSafeInteger(minor) || !Number.isSafeInteger(patch)) return undefined;\n\treturn [major, minor, patch] as const;\n}\n\nfunction plainVersion(value: string): string {\n\treturn value.replace(/^[vV]/u, \"\");\n}\n\n/**\n * Select the highest version satisfying a minimal range subset using the\n * ecosystem comparator (`comparePluginVersionsV1`): `undefined`/`latest` →\n * highest; `x.y.z` → exact full match (prerelease suffix included);\n * `^x.y.z` → >= x.y.z and < (x+1).0.0; `~x.y.z` → >= x.y.z and\n * < x.(y+1).0. Bounds use the comparator ordering (e.g. `1.0.0-alpha`\n * sorts below `1.0.0`).\n */\nexport function selectNpmPackageVersionV1(versions: readonly string[], range?: string): string | undefined {\n\tif (!Array.isArray(versions)) return undefined;\n\tlet candidates = versions.filter((value) => typeof value === \"string\" && parseVersionTriple(value) !== undefined);\n\tif (candidates.length === 0) return undefined;\n\tif (range === undefined || range === \"latest\") {\n\t\treturn candidates.reduce((left, right) => (comparePluginVersionsV1(right, left) > 0 ? right : left));\n\t}\n\tconst exact = plainVersion(range.replace(/^[=~^]/u, \"\"));\n\tif (!range.startsWith(\"^\") && !range.startsWith(\"~\"))\n\t\treturn candidates.find((value) => plainVersion(value) === exact);\n\tconst bound = parseVersionTriple(exact);\n\tif (bound === undefined) return undefined;\n\tconst [major, minor] = bound;\n\tconst upper = range.startsWith(\"^\") ? `${major + 1}.0.0` : `${major}.${minor + 1}.0`;\n\tcandidates = candidates.filter(\n\t\t(value) => comparePluginVersionsV1(value, exact) >= 0 && comparePluginVersionsV1(value, upper) < 0,\n\t);\n\tif (candidates.length === 0) return undefined;\n\treturn candidates.reduce((left, right) => (comparePluginVersionsV1(right, left) > 0 ? right : left));\n}\n\nfunction boundedPositive(value: number | undefined, fallback: number, maximum: number, label: string): number {\n\tconst result = value ?? fallback;\n\tif (!Number.isSafeInteger(result) || result <= 0 || result > maximum)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"{label} must be a positive integer at most {maximum}\", { label, maximum }),\n\t\t);\n\treturn result;\n}\n\nfunction registryOrigin(value: string): string {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"npm registry origin is invalid\"));\n\t}\n\tif (\n\t\t(parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") ||\n\t\tparsed.username !== \"\" ||\n\t\tparsed.password !== \"\"\n\t)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"npm registry origin must be http(s) without credentials\"),\n\t\t);\n\tif (parsed.pathname !== \"/\" || parsed.search !== \"\" || parsed.hash !== \"\")\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"npm registry origin must not include a path, query, or fragment\"),\n\t\t);\n\treturn parsed.origin;\n}\n\nfunction packumentUrl(registryOriginValue: string, name: string): URL {\n\tconst scopeAt = name.indexOf(\"/\");\n\tif (name.startsWith(\"@\") && scopeAt > 0) {\n\t\t// npm registry convention keeps the leading scope literal and percent\n\t\t// encodes the rest of the name, including the separating slash.\n\t\tconst scope = name.slice(0, scopeAt);\n\t\tconst packageName = name.slice(scopeAt + 1);\n\t\treturn new URL(`${registryOriginValue}/${scope}%2F${encodeURIComponent(packageName)}`);\n\t}\n\tif (scopeAt >= 0) throw new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"npm package name is invalid\"));\n\treturn new URL(`${registryOriginValue}/${encodeURIComponent(name)}`);\n}\n\nfunction tarballUrl(value: string): URL {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm tarball URL is invalid\"));\n\t}\n\tif (\n\t\t(parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") ||\n\t\tparsed.username !== \"\" ||\n\t\tparsed.password !== \"\"\n\t)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_response\",\n\t\t\tt(\"npm tarball URL must use http(s) without credentials\"),\n\t\t);\n\tif (parsed.hash !== \"\")\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm tarball URL must not include a fragment\"));\n\treturn parsed;\n}\n\nfunction isAbortLike(error: unknown): boolean {\n\treturn error instanceof Error && (error.name === \"AbortError\" || error.name === \"AbortSignalError\");\n}\n\ninterface RequestSignal {\n\treadonly signal: AbortSignal;\n\treadonly timedOut: () => boolean;\n\treadonly cleanup: () => void;\n}\n\nfunction requestSignal(parent: AbortSignal | undefined, timeoutMs: number): RequestSignal {\n\tconst controller = new AbortController();\n\tlet timedOut = false;\n\tconst abort = () => controller.abort(parent?.reason);\n\tif (parent?.aborted === true) abort();\n\telse parent?.addEventListener(\"abort\", abort, { once: true });\n\tconst timeout = setTimeout(() => {\n\t\ttimedOut = true;\n\t\tcontroller.abort();\n\t}, timeoutMs);\n\treturn {\n\t\tsignal: controller.signal,\n\t\ttimedOut: () => timedOut,\n\t\tcleanup: () => {\n\t\t\tclearTimeout(timeout);\n\t\t\tparent?.removeEventListener(\"abort\", abort);\n\t\t},\n\t};\n}\n\nfunction isJsonResponse(response: Response): boolean {\n\tconst contentType = response.headers.get(\"content-type\");\n\tif (contentType === null) return false;\n\tconst mediaType = contentType.split(\";\", 1)[0]?.trim().toLowerCase();\n\treturn mediaType === \"application/json\" || mediaType === \"application/vnd.npm.install-v1+json\";\n}\n\nasync function readBody(response: Response, maxBytes: number, signal: AbortSignal): Promise<Uint8Array> {\n\tif (response.body === null)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm registry response has no body\"));\n\tconst reader = response.body.getReader();\n\tconst chunks: Uint8Array[] = [];\n\tlet total = 0;\n\ttry {\n\t\tfor (;;) {\n\t\t\tif (signal.aborted) throw new DOMException(t(\"aborted\"), \"AbortError\");\n\t\t\tconst item = await reader.read();\n\t\t\tif (item.done) break;\n\t\t\ttotal += item.value.byteLength;\n\t\t\tif (total > maxBytes)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\t\t\"response_too_large\",\n\t\t\t\t\tt(\"npm registry response exceeds the configured size limit\"),\n\t\t\t\t);\n\t\t\tchunks.push(item.value);\n\t\t}\n\t} finally {\n\t\treader.releaseLock();\n\t}\n\tconst bytes = new Uint8Array(total);\n\tlet offset = 0;\n\tfor (const chunk of chunks) {\n\t\tbytes.set(chunk, offset);\n\t\toffset += chunk.byteLength;\n\t}\n\treturn bytes;\n}\n\ninterface PackumentVersionDistV1 {\n\treadonly tarball?: unknown;\n\treadonly integrity?: unknown;\n}\n\ninterface PackumentVersionV1 {\n\treadonly dist?: PackumentVersionDistV1;\n}\n\ninterface PackumentV1 {\n\treadonly versions?: Readonly<Record<string, PackumentVersionV1>>;\n}\n\nfunction parsePackument(bytes: Uint8Array): Readonly<Record<string, PackumentVersionV1>> {\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes));\n\t} catch {\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm registry response is not valid JSON\"));\n\t}\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value))\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm packument is invalid\"));\n\tconst packument = value as PackumentV1;\n\tif (typeof packument.versions !== \"object\" || packument.versions === null || Array.isArray(packument.versions))\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm packument has no version table\"));\n\treturn packument.versions;\n}\n\n/** Create a bounded npm registry reader. Version selection uses the ecosystem comparator. */\nexport function createNodeNpmRegistrySourceV1(options: NodeNpmRegistrySourceOptionsV1 = {}): NodeNpmRegistrySourceV1 {\n\tconst transport = options.fetch ?? globalThis.fetch;\n\tif (typeof transport !== \"function\")\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"Node fetch is unavailable\"));\n\tconst registry = registryOrigin(options.registry ?? DEFAULT_NPM_REGISTRY_V1);\n\tif (\n\t\toptions.token !== undefined &&\n\t\t(options.token.length === 0 || options.token.length > 4096 || /[\\r\\n\\s]/u.test(options.token))\n\t)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"npm registry token is invalid\"));\n\tconst token = options.token;\n\tconst timeoutMs = boundedPositive(\n\t\toptions.requestTimeoutMs,\n\t\tDEFAULT_TIMEOUT_MS_V1,\n\t\tMAX_TIMEOUT_MS_V1,\n\t\t\"requestTimeoutMs\",\n\t);\n\tconst maxResponseBytes = boundedPositive(\n\t\toptions.maxResponseBytes,\n\t\tDEFAULT_MAX_RESPONSE_BYTES_V1,\n\t\tMAX_RESPONSE_BYTES_V1,\n\t\t\"maxResponseBytes\",\n\t);\n\tconst maxTarballBytes = boundedPositive(\n\t\toptions.maxTarballBytes,\n\t\tDEFAULT_MAX_TARBALL_BYTES_V1,\n\t\tMAX_TARBALL_BYTES_V1,\n\t\t\"maxTarballBytes\",\n\t);\n\tconst maxRedirects = options.maxRedirects ?? DEFAULT_REDIRECTS_V1;\n\tif (!Number.isSafeInteger(maxRedirects) || maxRedirects < 0 || maxRedirects > MAX_REDIRECTS_V1)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"maxRedirects must be an integer between 0 and {max}\", { max: MAX_REDIRECTS_V1 }),\n\t\t);\n\tconst userAgent = options.userAgent ?? \"agent-forge-plugin-npm/1\";\n\tif (userAgent.length === 0 || userAgent.length > 256 || /[\\r\\n]/u.test(userAgent))\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"userAgent is invalid\"));\n\n\tconst fetchFollowingRedirects = async (\n\t\turl: URL,\n\t\theaders: Readonly<Record<string, string>>,\n\t\tparentSignal: AbortSignal | undefined,\n\t): Promise<{ readonly response: Response; readonly request: RequestSignal }> => {\n\t\tlet current = url;\n\t\tfor (let redirect = 0; ; redirect += 1) {\n\t\t\tconst request = requestSignal(parentSignal, timeoutMs);\n\t\t\tlet response: Response;\n\t\t\ttry {\n\t\t\t\tresponse = await transport(current.toString(), {\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\theaders: { accept: \"*/*\", \"user-agent\": userAgent, ...headers },\n\t\t\t\t\tredirect: \"manual\",\n\t\t\t\t\tsignal: request.signal,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\trequest.cleanup();\n\t\t\t\tif (request.timedOut())\n\t\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_timed_out\", t(\"npm registry request timed out\"));\n\t\t\t\tif (isAbortLike(error))\n\t\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"cancelled\", t(\"npm registry request was cancelled\"));\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_failed\", t(\"npm registry request failed\"));\n\t\t\t}\n\t\t\tif (!REDIRECT_STATUS.has(response.status)) return { response, request };\n\t\t\tconst location = response.headers.get(\"location\");\n\t\t\tawait response.body?.cancel().catch(() => undefined);\n\t\t\trequest.cleanup();\n\t\t\tif (location === null || redirect >= maxRedirects)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_failed\", t(\"npm registry redirect limit exceeded\"));\n\t\t\tcurrent = tarballUrl(new URL(location, current).toString());\n\t\t}\n\t};\n\n\tconst resolveNpmPackage = async (input: {\n\t\treadonly name: string;\n\t\treadonly range?: string;\n\t\treadonly signal?: AbortSignal;\n\t}): Promise<NodeNpmPackageResolutionV1> => {\n\t\tif (input.signal?.aborted === true)\n\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"cancelled\", t(\"npm registry request was cancelled\"));\n\t\tconst endpoint = packumentUrl(registry, input.name);\n\t\tconst authorization: Readonly<Record<string, string>> =\n\t\t\ttoken === undefined ? {} : { authorization: `Bearer ${token}` };\n\t\tconst { response, request } = await fetchFollowingRedirects(endpoint, authorization, input.signal);\n\t\ttry {\n\t\t\tif (response.status === 404 || response.status === 403)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"package_not_found\", t(\"npm package was not found on the registry\"));\n\t\t\tif (response.status < 200 || response.status >= 300)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_failed\", t(\"npm registry request did not succeed\"));\n\t\t\tif (!isJsonResponse(response))\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm registry response must be JSON\"));\n\t\t\tconst versions = parsePackument(await readBody(response, maxResponseBytes, request.signal));\n\t\t\tconst version = selectNpmPackageVersionV1(Object.keys(versions), input.range);\n\t\t\tconst dist = version === undefined ? undefined : versions[version]?.dist;\n\t\t\tif (\n\t\t\t\tversion === undefined ||\n\t\t\t\tdist === undefined ||\n\t\t\t\ttypeof dist.tarball !== \"string\" ||\n\t\t\t\tdist.tarball.length === 0\n\t\t\t) {\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\t\t\"version_not_found\",\n\t\t\t\t\tt(\"No npm package version matches the requested range\"),\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst integrityValue = dist.integrity;\n\t\t\tconst integrity =\n\t\t\t\ttypeof integrityValue === \"string\" && integrityValue.length > 0\n\t\t\t\t\t? sriToIntegrityV1(integrityValue)\n\t\t\t\t\t: undefined;\n\t\t\tif (integrity === undefined)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm package version has no integrity field\"));\n\t\t\treturn {\n\t\t\t\tversion,\n\t\t\t\ttarballUrl: tarballUrl(dist.tarball).toString(),\n\t\t\t\tintegrity,\n\t\t\t\tdistInfo: dist as Readonly<Record<string, unknown>>,\n\t\t\t};\n\t\t} finally {\n\t\t\tawait response.body?.cancel().catch(() => undefined);\n\t\t\trequest.cleanup();\n\t\t}\n\t};\n\n\tconst fetchTarball = async (input: { readonly url: string; readonly signal?: AbortSignal }): Promise<Uint8Array> => {\n\t\tif (input.signal?.aborted === true)\n\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"cancelled\", t(\"npm tarball download was cancelled\"));\n\t\tconst endpoint = tarballUrl(input.url);\n\t\tconst authorization: Readonly<Record<string, string>> =\n\t\t\ttoken === undefined ? {} : { authorization: `Bearer ${token}` };\n\t\tconst { response, request } = await fetchFollowingRedirects(endpoint, authorization, input.signal);\n\t\ttry {\n\t\t\tif (response.status < 200 || response.status >= 300)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_failed\", t(\"npm tarball download did not succeed\"));\n\t\t\treturn await readBody(response, maxTarballBytes, request.signal);\n\t\t} finally {\n\t\t\tawait response.body?.cancel().catch(() => undefined);\n\t\t\trequest.cleanup();\n\t\t}\n\t};\n\n\treturn { version: 1, registry, resolveNpmPackage, fetchTarball };\n}\n"]}
1
+ {"version":3,"file":"node-npm-registry-source.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-npm-registry-source.ts"],"names":[],"mappings":"AAsBA,MAAM,MAAM,gCAAgC,GACzC,WAAW,GACX,uBAAuB,GACvB,gBAAgB,GAChB,mBAAmB,GACnB,kBAAkB,GAClB,oBAAoB,GACpB,mBAAmB,GACnB,mBAAmB,GACnB,uBAAuB,GACvB,cAAc,CAAC;AAElB,qBAAa,4BAA6B,SAAQ,KAAK;IACtD,QAAQ,CAAC,IAAI,EAAE,gCAAgC,CAAC;IAChD,yFAAyF;IACzF,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAEpC,YACC,IAAI,EAAE,gCAAgC,EACtC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAAE,EAM3E;CACD;AAED,4FAA4F;AAC5F,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,SAAS,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC;IACvC,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,8BAA8B;IAC9C,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,2CAA2C;IAC3C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACzC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,iFAAiF;IACjF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,iBAAiB,EAAE,CAAC,KAAK,EAAE;QACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;KAC9B,KAAK,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC1C,QAAQ,CAAC,YAAY,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CAC/G;AAED,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,CAgBhE;AAgBD;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAmBzG;AAgND,6FAA6F;AAC7F,wBAAgB,6BAA6B,CAAC,OAAO,GAAE,8BAAmC,GAAG,uBAAuB,CAsJnH","sourcesContent":["import { t } from \"../../core/i18n/index.ts\";\nimport { comparePluginVersionsV1 } from \"./catalog.ts\";\n\n/**\n * Minimal npm registry (packument) source for plugin package acquisition\n * (design `插件独立分发与启动装配设计.md` §4.2). It is a two-step protocol:\n * resolve the packument to pick one version, then fetch the tarball. It does\n * not implement `PluginRegistrySourceV1.list()`; the signed registry sources\n * keep serving private deployments unchanged.\n */\n\nconst DEFAULT_NPM_REGISTRY_V1 = \"https://registry.npmjs.org\";\nconst DEFAULT_TIMEOUT_MS_V1 = 15_000;\nconst MAX_TIMEOUT_MS_V1 = 120_000;\nconst DEFAULT_MAX_RESPONSE_BYTES_V1 = 8 * 1024 * 1024;\nconst MAX_RESPONSE_BYTES_V1 = 16 * 1024 * 1024;\nconst DEFAULT_MAX_TARBALL_BYTES_V1 = 128 * 1024 * 1024;\nconst MAX_TARBALL_BYTES_V1 = 512 * 1024 * 1024;\nconst DEFAULT_REDIRECTS_V1 = 3;\nconst MAX_REDIRECTS_V1 = 5;\nconst REDIRECT_STATUS = new Set([301, 302, 303, 307, 308]);\n\nexport type NodeNpmRegistrySourceErrorCodeV1 =\n\t| \"cancelled\"\n\t| \"invalid_configuration\"\n\t| \"request_failed\"\n\t| \"request_timed_out\"\n\t| \"invalid_response\"\n\t| \"response_too_large\"\n\t| \"package_not_found\"\n\t| \"version_not_found\"\n\t| \"integrity_unsupported\"\n\t| \"rate_limited\";\n\nexport class NodeNpmRegistrySourceErrorV1 extends Error {\n\treadonly code: NodeNpmRegistrySourceErrorCodeV1;\n\t/** `Retry-After` seconds advertised by the registry; present only for `rate_limited`. */\n\treadonly retryAfterSeconds?: number;\n\n\tconstructor(\n\t\tcode: NodeNpmRegistrySourceErrorCodeV1,\n\t\tmessage: string,\n\t\toptions?: { readonly cause?: unknown; readonly retryAfterSeconds?: number },\n\t) {\n\t\tsuper(message, options?.cause === undefined ? undefined : { cause: options.cause });\n\t\tthis.name = \"NodeNpmRegistrySourceErrorV1\";\n\t\tthis.code = code;\n\t\tif (options?.retryAfterSeconds !== undefined) this.retryAfterSeconds = options.retryAfterSeconds;\n\t}\n}\n\n/** SRI integrity as hex plus its algorithm, aligned with the install host digest format. */\nexport interface NodeNpmIntegrityV1 {\n\treadonly algorithm: \"sha256\" | \"sha512\";\n\treadonly hex: string;\n}\n\nexport interface NodeNpmPackageResolutionV1 {\n\treadonly version: string;\n\treadonly tarballUrl: string;\n\treadonly integrity: NodeNpmIntegrityV1;\n\t/** Raw `dist` fields of the selected version. */\n\treadonly distInfo: Readonly<Record<string, unknown>>;\n}\n\nexport interface NodeNpmRegistrySourceOptionsV1 {\n\t/** Bare http(s) registry origin; defaults to the npm public registry. */\n\treadonly registry?: string;\n\t/** Bearer token for private registries. */\n\treadonly token?: string;\n\t/** Real fetch or a deterministic test replacement. */\n\treadonly fetch?: typeof globalThis.fetch;\n\treadonly requestTimeoutMs?: number;\n\treadonly maxResponseBytes?: number;\n\treadonly maxTarballBytes?: number;\n\treadonly maxRedirects?: number;\n\treadonly userAgent?: string;\n}\n\nexport interface NodeNpmRegistrySourceV1 {\n\treadonly version: 1;\n\t/** Sanitized bare registry origin (no credentials, path, query, or fragment). */\n\treadonly registry: string;\n\treadonly resolveNpmPackage: (input: {\n\t\treadonly name: string;\n\t\treadonly range?: string;\n\t\treadonly signal?: AbortSignal;\n\t}) => Promise<NodeNpmPackageResolutionV1>;\n\treadonly fetchTarball: (input: { readonly url: string; readonly signal?: AbortSignal }) => Promise<Uint8Array>;\n}\n\n/** Convert an npm SRI string (`sha512-<base64>`, `sha256-<base64>`) to hex form. */\nexport function sriToIntegrityV1(sri: string): NodeNpmIntegrityV1 {\n\tconst match = /^(sha512|sha256)-([A-Za-z0-9+/]+={0,2})$/u.exec(sri.trim());\n\tif (match === null)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"integrity_unsupported\", t(\"npm integrity algorithm is unsupported\"));\n\tconst algorithm = match[1] as \"sha512\" | \"sha256\";\n\tlet raw: Buffer;\n\ttry {\n\t\traw = Buffer.from(match[2]!, \"base64\");\n\t} catch {\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"integrity_unsupported\", t(\"npm integrity encoding is invalid\"));\n\t}\n\tif ((algorithm === \"sha256\" && raw.byteLength !== 32) || (algorithm === \"sha512\" && raw.byteLength !== 64))\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"integrity_unsupported\", t(\"npm integrity length is invalid\"));\n\tconst hex = raw.toString(\"hex\").toLowerCase();\n\tif (hex.length === 0) throw new NodeNpmRegistrySourceErrorV1(\"integrity_unsupported\", t(\"npm integrity is invalid\"));\n\treturn { algorithm, hex };\n}\n\nfunction parseVersionTriple(value: string): readonly [number, number, number] | undefined {\n\tconst match = /^(\\d+)\\.(\\d+)\\.(\\d+)/u.exec(value.replace(/^[vV]/u, \"\"));\n\tif (match === null) return undefined;\n\tconst major = Number.parseInt(match[1]!, 10);\n\tconst minor = Number.parseInt(match[2]!, 10);\n\tconst patch = Number.parseInt(match[3]!, 10);\n\tif (!Number.isSafeInteger(major) || !Number.isSafeInteger(minor) || !Number.isSafeInteger(patch)) return undefined;\n\treturn [major, minor, patch] as const;\n}\n\nfunction plainVersion(value: string): string {\n\treturn value.replace(/^[vV]/u, \"\");\n}\n\n/**\n * Select the highest version satisfying a minimal range subset using the\n * ecosystem comparator (`comparePluginVersionsV1`): `undefined`/`latest` →\n * highest; `x.y.z` → exact full match (prerelease suffix included);\n * `^x.y.z` → >= x.y.z and < (x+1).0.0; `~x.y.z` → >= x.y.z and\n * < x.(y+1).0. Bounds use the comparator ordering (e.g. `1.0.0-alpha`\n * sorts below `1.0.0`).\n */\nexport function selectNpmPackageVersionV1(versions: readonly string[], range?: string): string | undefined {\n\tif (!Array.isArray(versions)) return undefined;\n\tlet candidates = versions.filter((value) => typeof value === \"string\" && parseVersionTriple(value) !== undefined);\n\tif (candidates.length === 0) return undefined;\n\tif (range === undefined || range === \"latest\") {\n\t\treturn candidates.reduce((left, right) => (comparePluginVersionsV1(right, left) > 0 ? right : left));\n\t}\n\tconst exact = plainVersion(range.replace(/^[=~^]/u, \"\"));\n\tif (!range.startsWith(\"^\") && !range.startsWith(\"~\"))\n\t\treturn candidates.find((value) => plainVersion(value) === exact);\n\tconst bound = parseVersionTriple(exact);\n\tif (bound === undefined) return undefined;\n\tconst [major, minor] = bound;\n\tconst upper = range.startsWith(\"^\") ? `${major + 1}.0.0` : `${major}.${minor + 1}.0`;\n\tcandidates = candidates.filter(\n\t\t(value) => comparePluginVersionsV1(value, exact) >= 0 && comparePluginVersionsV1(value, upper) < 0,\n\t);\n\tif (candidates.length === 0) return undefined;\n\treturn candidates.reduce((left, right) => (comparePluginVersionsV1(right, left) > 0 ? right : left));\n}\n\nfunction boundedPositive(value: number | undefined, fallback: number, maximum: number, label: string): number {\n\tconst result = value ?? fallback;\n\tif (!Number.isSafeInteger(result) || result <= 0 || result > maximum)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"{label} must be a positive integer at most {maximum}\", { label, maximum }),\n\t\t);\n\treturn result;\n}\n\nfunction registryOrigin(value: string): string {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"npm registry origin is invalid\"));\n\t}\n\tif (\n\t\t(parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") ||\n\t\tparsed.username !== \"\" ||\n\t\tparsed.password !== \"\"\n\t)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"npm registry origin must be http(s) without credentials\"),\n\t\t);\n\tif (parsed.pathname !== \"/\" || parsed.search !== \"\" || parsed.hash !== \"\")\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"npm registry origin must not include a path, query, or fragment\"),\n\t\t);\n\treturn parsed.origin;\n}\n\nfunction packumentUrl(registryOriginValue: string, name: string): URL {\n\tconst scopeAt = name.indexOf(\"/\");\n\tif (name.startsWith(\"@\") && scopeAt > 0) {\n\t\t// npm registry convention keeps the leading scope literal and percent\n\t\t// encodes the rest of the name, including the separating slash.\n\t\tconst scope = name.slice(0, scopeAt);\n\t\tconst packageName = name.slice(scopeAt + 1);\n\t\treturn new URL(`${registryOriginValue}/${scope}%2F${encodeURIComponent(packageName)}`);\n\t}\n\tif (scopeAt >= 0) throw new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"npm package name is invalid\"));\n\treturn new URL(`${registryOriginValue}/${encodeURIComponent(name)}`);\n}\n\nfunction tarballUrl(value: string): URL {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm tarball URL is invalid\"));\n\t}\n\tif (\n\t\t(parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") ||\n\t\tparsed.username !== \"\" ||\n\t\tparsed.password !== \"\"\n\t)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_response\",\n\t\t\tt(\"npm tarball URL must use http(s) without credentials\"),\n\t\t);\n\tif (parsed.hash !== \"\")\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm tarball URL must not include a fragment\"));\n\treturn parsed;\n}\n\nfunction isAbortLike(error: unknown): boolean {\n\treturn error instanceof Error && (error.name === \"AbortError\" || error.name === \"AbortSignalError\");\n}\n\ninterface RequestSignal {\n\treadonly signal: AbortSignal;\n\treadonly timedOut: () => boolean;\n\treadonly cleanup: () => void;\n}\n\nfunction requestSignal(parent: AbortSignal | undefined, timeoutMs: number): RequestSignal {\n\tconst controller = new AbortController();\n\tlet timedOut = false;\n\tconst abort = () => controller.abort(parent?.reason);\n\tif (parent?.aborted === true) abort();\n\telse parent?.addEventListener(\"abort\", abort, { once: true });\n\tconst timeout = setTimeout(() => {\n\t\ttimedOut = true;\n\t\tcontroller.abort();\n\t}, timeoutMs);\n\treturn {\n\t\tsignal: controller.signal,\n\t\ttimedOut: () => timedOut,\n\t\tcleanup: () => {\n\t\t\tclearTimeout(timeout);\n\t\t\tparent?.removeEventListener(\"abort\", abort);\n\t\t},\n\t};\n}\n\nfunction isJsonResponse(response: Response): boolean {\n\tconst contentType = response.headers.get(\"content-type\");\n\tif (contentType === null) return false;\n\tconst mediaType = contentType.split(\";\", 1)[0]?.trim().toLowerCase();\n\treturn mediaType === \"application/json\" || mediaType === \"application/vnd.npm.install-v1+json\";\n}\n\n/**\n * Rate-limit verdict for 429/403 responses, isomorphic with the release\n * source: any 429, and a 403 whose `X-RateLimit-Remaining` is exactly `0`.\n * `Retry-After` passes through as whole seconds when present and integer-like;\n * absent or malformed headers stay absent.\n */\nfunction rateLimitState(response: Response): { readonly limited: boolean; readonly retryAfterSeconds?: number } {\n\tconst limited =\n\t\tresponse.status === 429 || (response.status === 403 && response.headers.get(\"x-ratelimit-remaining\") === \"0\");\n\tif (!limited) return { limited: false };\n\tconst retryAfter = response.headers.get(\"retry-after\");\n\tconst seconds = retryAfter === null ? Number.NaN : Number.parseInt(retryAfter, 10);\n\tif (!Number.isSafeInteger(seconds) || seconds < 0) return { limited: true };\n\treturn { limited: true, retryAfterSeconds: seconds };\n}\n\nfunction rateLimitError(limit: { readonly retryAfterSeconds?: number }): NodeNpmRegistrySourceErrorV1 {\n\tconst message =\n\t\tlimit.retryAfterSeconds === undefined\n\t\t\t? t(\"npm registry rate limit was exceeded\")\n\t\t\t: `${t(\"npm registry rate limit was exceeded\")} (retry after ${limit.retryAfterSeconds}s)`;\n\treturn new NodeNpmRegistrySourceErrorV1(\"rate_limited\", message, {\n\t\t...(limit.retryAfterSeconds === undefined ? {} : { retryAfterSeconds: limit.retryAfterSeconds }),\n\t});\n}\n\n/**\n * Read a bounded body. Aborts are classified by their owner: the module's own\n * timeout timer surfaces as `request_timed_out`, an externally cancelled\n * signal as `cancelled` — the raw AbortError would otherwise fall through to\n * the generic download failure and hide the real cause.\n */\nasync function readBody(response: Response, maxBytes: number, request: RequestSignal): Promise<Uint8Array> {\n\tif (response.body === null)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm registry response has no body\"));\n\tconst reader = response.body.getReader();\n\tconst chunks: Uint8Array[] = [];\n\tlet total = 0;\n\tconst abortError = (): NodeNpmRegistrySourceErrorV1 =>\n\t\trequest.timedOut()\n\t\t\t? new NodeNpmRegistrySourceErrorV1(\"request_timed_out\", t(\"npm registry request timed out\"))\n\t\t\t: new NodeNpmRegistrySourceErrorV1(\"cancelled\", t(\"npm registry request was cancelled\"));\n\ttry {\n\t\tfor (;;) {\n\t\t\tif (request.signal.aborted) throw abortError();\n\t\t\tlet item: Awaited<ReturnType<typeof reader.read>>;\n\t\t\ttry {\n\t\t\t\titem = await reader.read();\n\t\t\t} catch (error) {\n\t\t\t\tif (request.signal.aborted) throw abortError();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tif (item.done) break;\n\t\t\ttotal += item.value.byteLength;\n\t\t\tif (total > maxBytes)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\t\t\"response_too_large\",\n\t\t\t\t\tt(\"npm registry response exceeds the configured size limit\"),\n\t\t\t\t);\n\t\t\tchunks.push(item.value);\n\t\t}\n\t} finally {\n\t\treader.releaseLock();\n\t}\n\tconst bytes = new Uint8Array(total);\n\tlet offset = 0;\n\tfor (const chunk of chunks) {\n\t\tbytes.set(chunk, offset);\n\t\toffset += chunk.byteLength;\n\t}\n\treturn bytes;\n}\n\ninterface PackumentVersionDistV1 {\n\treadonly tarball?: unknown;\n\treadonly integrity?: unknown;\n}\n\ninterface PackumentVersionV1 {\n\treadonly dist?: PackumentVersionDistV1;\n}\n\ninterface PackumentV1 {\n\treadonly versions?: Readonly<Record<string, PackumentVersionV1>>;\n}\n\nfunction parsePackument(bytes: Uint8Array): Readonly<Record<string, PackumentVersionV1>> {\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes));\n\t} catch {\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm registry response is not valid JSON\"));\n\t}\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value))\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm packument is invalid\"));\n\tconst packument = value as PackumentV1;\n\tif (typeof packument.versions !== \"object\" || packument.versions === null || Array.isArray(packument.versions))\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm packument has no version table\"));\n\treturn packument.versions;\n}\n\n/** Create a bounded npm registry reader. Version selection uses the ecosystem comparator. */\nexport function createNodeNpmRegistrySourceV1(options: NodeNpmRegistrySourceOptionsV1 = {}): NodeNpmRegistrySourceV1 {\n\tconst transport = options.fetch ?? globalThis.fetch;\n\tif (typeof transport !== \"function\")\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"Node fetch is unavailable\"));\n\tconst registry = registryOrigin(options.registry ?? DEFAULT_NPM_REGISTRY_V1);\n\tif (\n\t\toptions.token !== undefined &&\n\t\t(options.token.length === 0 || options.token.length > 4096 || /[\\r\\n\\s]/u.test(options.token))\n\t)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"npm registry token is invalid\"));\n\tconst token = options.token;\n\tconst timeoutMs = boundedPositive(\n\t\toptions.requestTimeoutMs,\n\t\tDEFAULT_TIMEOUT_MS_V1,\n\t\tMAX_TIMEOUT_MS_V1,\n\t\t\"requestTimeoutMs\",\n\t);\n\tconst maxResponseBytes = boundedPositive(\n\t\toptions.maxResponseBytes,\n\t\tDEFAULT_MAX_RESPONSE_BYTES_V1,\n\t\tMAX_RESPONSE_BYTES_V1,\n\t\t\"maxResponseBytes\",\n\t);\n\tconst maxTarballBytes = boundedPositive(\n\t\toptions.maxTarballBytes,\n\t\tDEFAULT_MAX_TARBALL_BYTES_V1,\n\t\tMAX_TARBALL_BYTES_V1,\n\t\t\"maxTarballBytes\",\n\t);\n\tconst maxRedirects = options.maxRedirects ?? DEFAULT_REDIRECTS_V1;\n\tif (!Number.isSafeInteger(maxRedirects) || maxRedirects < 0 || maxRedirects > MAX_REDIRECTS_V1)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"maxRedirects must be an integer between 0 and {max}\", { max: MAX_REDIRECTS_V1 }),\n\t\t);\n\tconst userAgent = options.userAgent ?? \"agent-forge-plugin-npm/1\";\n\tif (userAgent.length === 0 || userAgent.length > 256 || /[\\r\\n]/u.test(userAgent))\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"userAgent is invalid\"));\n\n\tconst fetchFollowingRedirects = async (\n\t\turl: URL,\n\t\theaders: Readonly<Record<string, string>>,\n\t\tparentSignal: AbortSignal | undefined,\n\t): Promise<{ readonly response: Response; readonly request: RequestSignal }> => {\n\t\tlet current = url;\n\t\tfor (let redirect = 0; ; redirect += 1) {\n\t\t\tconst request = requestSignal(parentSignal, timeoutMs);\n\t\t\tlet response: Response;\n\t\t\ttry {\n\t\t\t\tresponse = await transport(current.toString(), {\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\theaders: { accept: \"*/*\", \"user-agent\": userAgent, ...headers },\n\t\t\t\t\tredirect: \"manual\",\n\t\t\t\t\tsignal: request.signal,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\trequest.cleanup();\n\t\t\t\tif (request.timedOut())\n\t\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_timed_out\", t(\"npm registry request timed out\"));\n\t\t\t\tif (isAbortLike(error))\n\t\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"cancelled\", t(\"npm registry request was cancelled\"));\n\t\t\t\t// Keep the transport failure as `cause`; replacing it outright made\n\t\t\t\t// connection-level failures (DNS, TLS, ECONNREFUSED) undiagnosable.\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_failed\", t(\"npm registry request failed\"), {\n\t\t\t\t\tcause: error,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!REDIRECT_STATUS.has(response.status)) return { response, request };\n\t\t\tconst location = response.headers.get(\"location\");\n\t\t\tawait response.body?.cancel().catch(() => undefined);\n\t\t\trequest.cleanup();\n\t\t\tif (location === null || redirect >= maxRedirects)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_failed\", t(\"npm registry redirect limit exceeded\"));\n\t\t\tcurrent = tarballUrl(new URL(location, current).toString());\n\t\t}\n\t};\n\n\tconst resolveNpmPackage = async (input: {\n\t\treadonly name: string;\n\t\treadonly range?: string;\n\t\treadonly signal?: AbortSignal;\n\t}): Promise<NodeNpmPackageResolutionV1> => {\n\t\tif (input.signal?.aborted === true)\n\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"cancelled\", t(\"npm registry request was cancelled\"));\n\t\tconst endpoint = packumentUrl(registry, input.name);\n\t\tconst authorization: Readonly<Record<string, string>> =\n\t\t\ttoken === undefined ? {} : { authorization: `Bearer ${token}` };\n\t\tconst { response, request } = await fetchFollowingRedirects(endpoint, authorization, input.signal);\n\t\ttry {\n\t\t\tconst limit = rateLimitState(response);\n\t\t\tif (limit.limited) throw rateLimitError(limit);\n\t\t\tif (response.status === 404 || response.status === 403)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"package_not_found\", t(\"npm package was not found on the registry\"));\n\t\t\tif (response.status < 200 || response.status >= 300)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_failed\", t(\"npm registry request did not succeed\"));\n\t\t\tif (!isJsonResponse(response))\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm registry response must be JSON\"));\n\t\t\tconst versions = parsePackument(await readBody(response, maxResponseBytes, request));\n\t\t\tconst version = selectNpmPackageVersionV1(Object.keys(versions), input.range);\n\t\t\tconst dist = version === undefined ? undefined : versions[version]?.dist;\n\t\t\tif (\n\t\t\t\tversion === undefined ||\n\t\t\t\tdist === undefined ||\n\t\t\t\ttypeof dist.tarball !== \"string\" ||\n\t\t\t\tdist.tarball.length === 0\n\t\t\t) {\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\t\t\"version_not_found\",\n\t\t\t\t\tt(\"No npm package version matches the requested range\"),\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst integrityValue = dist.integrity;\n\t\t\tconst integrity =\n\t\t\t\ttypeof integrityValue === \"string\" && integrityValue.length > 0\n\t\t\t\t\t? sriToIntegrityV1(integrityValue)\n\t\t\t\t\t: undefined;\n\t\t\tif (integrity === undefined)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm package version has no integrity field\"));\n\t\t\treturn {\n\t\t\t\tversion,\n\t\t\t\ttarballUrl: tarballUrl(dist.tarball).toString(),\n\t\t\t\tintegrity,\n\t\t\t\tdistInfo: dist as Readonly<Record<string, unknown>>,\n\t\t\t};\n\t\t} finally {\n\t\t\tawait response.body?.cancel().catch(() => undefined);\n\t\t\trequest.cleanup();\n\t\t}\n\t};\n\n\tconst fetchTarball = async (input: { readonly url: string; readonly signal?: AbortSignal }): Promise<Uint8Array> => {\n\t\tif (input.signal?.aborted === true)\n\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"cancelled\", t(\"npm tarball download was cancelled\"));\n\t\tconst endpoint = tarballUrl(input.url);\n\t\tconst authorization: Readonly<Record<string, string>> =\n\t\t\ttoken === undefined ? {} : { authorization: `Bearer ${token}` };\n\t\tconst { response, request } = await fetchFollowingRedirects(endpoint, authorization, input.signal);\n\t\ttry {\n\t\t\tconst limit = rateLimitState(response);\n\t\t\tif (limit.limited) throw rateLimitError(limit);\n\t\t\tif (response.status < 200 || response.status >= 300)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_failed\", t(\"npm tarball download did not succeed\"));\n\t\t\treturn await readBody(response, maxTarballBytes, request);\n\t\t} finally {\n\t\t\tawait response.body?.cancel().catch(() => undefined);\n\t\t\trequest.cleanup();\n\t\t}\n\t};\n\n\treturn { version: 1, registry, resolveNpmPackage, fetchTarball };\n}\n"]}
@@ -19,10 +19,14 @@ const MAX_REDIRECTS_V1 = 5;
19
19
  const REDIRECT_STATUS = new Set([301, 302, 303, 307, 308]);
20
20
  export class NodeNpmRegistrySourceErrorV1 extends Error {
21
21
  code;
22
- constructor(code, message) {
23
- super(message);
22
+ /** `Retry-After` seconds advertised by the registry; present only for `rate_limited`. */
23
+ retryAfterSeconds;
24
+ constructor(code, message, options) {
25
+ super(message, options?.cause === undefined ? undefined : { cause: options.cause });
24
26
  this.name = "NodeNpmRegistrySourceErrorV1";
25
27
  this.code = code;
28
+ if (options?.retryAfterSeconds !== undefined)
29
+ this.retryAfterSeconds = options.retryAfterSeconds;
26
30
  }
27
31
  }
28
32
  /** Convert an npm SRI string (`sha512-<base64>`, `sha256-<base64>`) to hex form. */
@@ -171,17 +175,58 @@ function isJsonResponse(response) {
171
175
  const mediaType = contentType.split(";", 1)[0]?.trim().toLowerCase();
172
176
  return mediaType === "application/json" || mediaType === "application/vnd.npm.install-v1+json";
173
177
  }
174
- async function readBody(response, maxBytes, signal) {
178
+ /**
179
+ * Rate-limit verdict for 429/403 responses, isomorphic with the release
180
+ * source: any 429, and a 403 whose `X-RateLimit-Remaining` is exactly `0`.
181
+ * `Retry-After` passes through as whole seconds when present and integer-like;
182
+ * absent or malformed headers stay absent.
183
+ */
184
+ function rateLimitState(response) {
185
+ const limited = response.status === 429 || (response.status === 403 && response.headers.get("x-ratelimit-remaining") === "0");
186
+ if (!limited)
187
+ return { limited: false };
188
+ const retryAfter = response.headers.get("retry-after");
189
+ const seconds = retryAfter === null ? Number.NaN : Number.parseInt(retryAfter, 10);
190
+ if (!Number.isSafeInteger(seconds) || seconds < 0)
191
+ return { limited: true };
192
+ return { limited: true, retryAfterSeconds: seconds };
193
+ }
194
+ function rateLimitError(limit) {
195
+ const message = limit.retryAfterSeconds === undefined
196
+ ? t("npm registry rate limit was exceeded")
197
+ : `${t("npm registry rate limit was exceeded")} (retry after ${limit.retryAfterSeconds}s)`;
198
+ return new NodeNpmRegistrySourceErrorV1("rate_limited", message, {
199
+ ...(limit.retryAfterSeconds === undefined ? {} : { retryAfterSeconds: limit.retryAfterSeconds }),
200
+ });
201
+ }
202
+ /**
203
+ * Read a bounded body. Aborts are classified by their owner: the module's own
204
+ * timeout timer surfaces as `request_timed_out`, an externally cancelled
205
+ * signal as `cancelled` — the raw AbortError would otherwise fall through to
206
+ * the generic download failure and hide the real cause.
207
+ */
208
+ async function readBody(response, maxBytes, request) {
175
209
  if (response.body === null)
176
210
  throw new NodeNpmRegistrySourceErrorV1("invalid_response", t("npm registry response has no body"));
177
211
  const reader = response.body.getReader();
178
212
  const chunks = [];
179
213
  let total = 0;
214
+ const abortError = () => request.timedOut()
215
+ ? new NodeNpmRegistrySourceErrorV1("request_timed_out", t("npm registry request timed out"))
216
+ : new NodeNpmRegistrySourceErrorV1("cancelled", t("npm registry request was cancelled"));
180
217
  try {
181
218
  for (;;) {
182
- if (signal.aborted)
183
- throw new DOMException(t("aborted"), "AbortError");
184
- const item = await reader.read();
219
+ if (request.signal.aborted)
220
+ throw abortError();
221
+ let item;
222
+ try {
223
+ item = await reader.read();
224
+ }
225
+ catch (error) {
226
+ if (request.signal.aborted)
227
+ throw abortError();
228
+ throw error;
229
+ }
185
230
  if (item.done)
186
231
  break;
187
232
  total += item.value.byteLength;
@@ -254,7 +299,11 @@ export function createNodeNpmRegistrySourceV1(options = {}) {
254
299
  throw new NodeNpmRegistrySourceErrorV1("request_timed_out", t("npm registry request timed out"));
255
300
  if (isAbortLike(error))
256
301
  throw new NodeNpmRegistrySourceErrorV1("cancelled", t("npm registry request was cancelled"));
257
- throw new NodeNpmRegistrySourceErrorV1("request_failed", t("npm registry request failed"));
302
+ // Keep the transport failure as `cause`; replacing it outright made
303
+ // connection-level failures (DNS, TLS, ECONNREFUSED) undiagnosable.
304
+ throw new NodeNpmRegistrySourceErrorV1("request_failed", t("npm registry request failed"), {
305
+ cause: error,
306
+ });
258
307
  }
259
308
  if (!REDIRECT_STATUS.has(response.status))
260
309
  return { response, request };
@@ -273,13 +322,16 @@ export function createNodeNpmRegistrySourceV1(options = {}) {
273
322
  const authorization = token === undefined ? {} : { authorization: `Bearer ${token}` };
274
323
  const { response, request } = await fetchFollowingRedirects(endpoint, authorization, input.signal);
275
324
  try {
325
+ const limit = rateLimitState(response);
326
+ if (limit.limited)
327
+ throw rateLimitError(limit);
276
328
  if (response.status === 404 || response.status === 403)
277
329
  throw new NodeNpmRegistrySourceErrorV1("package_not_found", t("npm package was not found on the registry"));
278
330
  if (response.status < 200 || response.status >= 300)
279
331
  throw new NodeNpmRegistrySourceErrorV1("request_failed", t("npm registry request did not succeed"));
280
332
  if (!isJsonResponse(response))
281
333
  throw new NodeNpmRegistrySourceErrorV1("invalid_response", t("npm registry response must be JSON"));
282
- const versions = parsePackument(await readBody(response, maxResponseBytes, request.signal));
334
+ const versions = parsePackument(await readBody(response, maxResponseBytes, request));
283
335
  const version = selectNpmPackageVersionV1(Object.keys(versions), input.range);
284
336
  const dist = version === undefined ? undefined : versions[version]?.dist;
285
337
  if (version === undefined ||
@@ -313,9 +365,12 @@ export function createNodeNpmRegistrySourceV1(options = {}) {
313
365
  const authorization = token === undefined ? {} : { authorization: `Bearer ${token}` };
314
366
  const { response, request } = await fetchFollowingRedirects(endpoint, authorization, input.signal);
315
367
  try {
368
+ const limit = rateLimitState(response);
369
+ if (limit.limited)
370
+ throw rateLimitError(limit);
316
371
  if (response.status < 200 || response.status >= 300)
317
372
  throw new NodeNpmRegistrySourceErrorV1("request_failed", t("npm tarball download did not succeed"));
318
- return await readBody(response, maxTarballBytes, request.signal);
373
+ return await readBody(response, maxTarballBytes, request);
319
374
  }
320
375
  finally {
321
376
  await response.body?.cancel().catch(() => undefined);
@@ -1 +1 @@
1
- {"version":3,"file":"node-npm-registry-source.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-npm-registry-source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,0BAA0B,CAAC;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAEvD;;;;;;GAMG;AAEH,MAAM,uBAAuB,GAAG,4BAA4B,CAAC;AAC7D,MAAM,qBAAqB,GAAG,MAAM,CAAC;AACrC,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAClC,MAAM,6BAA6B,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AACtD,MAAM,qBAAqB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAC/C,MAAM,4BAA4B,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;AACvD,MAAM,oBAAoB,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;AAC/C,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAC/B,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAC3B,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAa3D,MAAM,OAAO,4BAA6B,SAAQ,KAAK;IAC7C,IAAI,CAAmC;IAEhD,YAAY,IAAsC,EAAE,OAAe,EAAE;QACpE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC;QAC3C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAAA,CACjB;CACD;AA0CD,oFAAoF;AACpF,MAAM,UAAU,gBAAgB,CAAC,GAAW,EAAsB;IACjE,MAAM,KAAK,GAAG,2CAA2C,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3E,IAAI,KAAK,KAAK,IAAI;QACjB,MAAM,IAAI,4BAA4B,CAAC,uBAAuB,EAAE,CAAC,CAAC,wCAAwC,CAAC,CAAC,CAAC;IAC9G,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAwB,CAAC;IAClD,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACJ,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,QAAQ,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,4BAA4B,CAAC,uBAAuB,EAAE,CAAC,CAAC,mCAAmC,CAAC,CAAC,CAAC;IACzG,CAAC;IACD,IAAI,CAAC,SAAS,KAAK,QAAQ,IAAI,GAAG,CAAC,UAAU,KAAK,EAAE,CAAC,IAAI,CAAC,SAAS,KAAK,QAAQ,IAAI,GAAG,CAAC,UAAU,KAAK,EAAE,CAAC;QACzG,MAAM,IAAI,4BAA4B,CAAC,uBAAuB,EAAE,CAAC,CAAC,iCAAiC,CAAC,CAAC,CAAC;IACvG,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;IAC9C,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,4BAA4B,CAAC,uBAAuB,EAAE,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC;IACrH,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;AAAA,CAC1B;AAED,SAAS,kBAAkB,CAAC,KAAa,EAAiD;IACzF,MAAM,KAAK,GAAG,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC;IACxE,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACrC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,CAAC;IAC7C,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACnH,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAU,CAAC;AAAA,CACtC;AAED,SAAS,YAAY,CAAC,KAAa,EAAU;IAC5C,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAAA,CACnC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,yBAAyB,CAAC,QAA2B,EAAE,KAAc,EAAsB;IAC1G,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/C,IAAI,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,kBAAkB,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC,CAAC;IAClH,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/C,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,uBAAuB,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACtG,CAAC;IACD,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;IACzD,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;QACnD,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IACxC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,KAAK,CAAC;IAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,KAAK,GAAG,CAAC,IAAI,CAAC;IACrF,UAAU,GAAG,UAAU,CAAC,MAAM,CAC7B,CAAC,KAAK,EAAE,EAAE,CAAC,uBAAuB,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,uBAAuB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAClG,CAAC;IACF,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,uBAAuB,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAAA,CACrG;AAED,SAAS,eAAe,CAAC,KAAyB,EAAE,QAAgB,EAAE,OAAe,EAAE,KAAa,EAAU;IAC7G,MAAM,MAAM,GAAG,KAAK,IAAI,QAAQ,CAAC;IACjC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,IAAI,MAAM,GAAG,OAAO;QACnE,MAAM,IAAI,4BAA4B,CACrC,uBAAuB,EACvB,CAAC,CAAC,sDAAsD,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAC7E,CAAC;IACH,OAAO,MAAM,CAAC;AAAA,CACd;AAED,SAAS,cAAc,CAAC,KAAa,EAAU;IAC9C,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACJ,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,4BAA4B,CAAC,uBAAuB,EAAE,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC;IACtG,CAAC;IACD,IACC,CAAC,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC;QAC7D,MAAM,CAAC,QAAQ,KAAK,EAAE;QACtB,MAAM,CAAC,QAAQ,KAAK,EAAE;QAEtB,MAAM,IAAI,4BAA4B,CACrC,uBAAuB,EACvB,CAAC,CAAC,yDAAyD,CAAC,CAC5D,CAAC;IACH,IAAI,MAAM,CAAC,QAAQ,KAAK,GAAG,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,IAAI,MAAM,CAAC,IAAI,KAAK,EAAE;QACxE,MAAM,IAAI,4BAA4B,CACrC,uBAAuB,EACvB,CAAC,CAAC,iEAAiE,CAAC,CACpE,CAAC;IACH,OAAO,MAAM,CAAC,MAAM,CAAC;AAAA,CACrB;AAED,SAAS,YAAY,CAAC,mBAA2B,EAAE,IAAY,EAAO;IACrE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QACzC,sEAAsE;QACtE,gEAAgE;QAChE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QACrC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;QAC5C,OAAO,IAAI,GAAG,CAAC,GAAG,mBAAmB,IAAI,KAAK,MAAM,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,IAAI,OAAO,IAAI,CAAC;QAAE,MAAM,IAAI,4BAA4B,CAAC,uBAAuB,EAAE,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC;IACpH,OAAO,IAAI,GAAG,CAAC,GAAG,mBAAmB,IAAI,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAAA,CACrE;AAED,SAAS,UAAU,CAAC,KAAa,EAAO;IACvC,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACJ,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,4BAA4B,CAAC,kBAAkB,EAAE,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC;IAC7F,CAAC;IACD,IACC,CAAC,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC;QAC7D,MAAM,CAAC,QAAQ,KAAK,EAAE;QACtB,MAAM,CAAC,QAAQ,KAAK,EAAE;QAEtB,MAAM,IAAI,4BAA4B,CACrC,kBAAkB,EAClB,CAAC,CAAC,sDAAsD,CAAC,CACzD,CAAC;IACH,IAAI,MAAM,CAAC,IAAI,KAAK,EAAE;QACrB,MAAM,IAAI,4BAA4B,CAAC,kBAAkB,EAAE,CAAC,CAAC,6CAA6C,CAAC,CAAC,CAAC;IAC9G,OAAO,MAAM,CAAC;AAAA,CACd;AAED,SAAS,WAAW,CAAC,KAAc,EAAW;IAC7C,OAAO,KAAK,YAAY,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,kBAAkB,CAAC,CAAC;AAAA,CACpG;AAQD,SAAS,aAAa,CAAC,MAA+B,EAAE,SAAiB,EAAiB;IACzF,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrD,IAAI,MAAM,EAAE,OAAO,KAAK,IAAI;QAAE,KAAK,EAAE,CAAC;;QACjC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC;QAChC,QAAQ,GAAG,IAAI,CAAC;QAChB,UAAU,CAAC,KAAK,EAAE,CAAC;IAAA,CACnB,EAAE,SAAS,CAAC,CAAC;IACd,OAAO;QACN,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ;QACxB,OAAO,EAAE,GAAG,EAAE,CAAC;YACd,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAAA,CAC5C;KACD,CAAC;AAAA,CACF;AAED,SAAS,cAAc,CAAC,QAAkB,EAAW;IACpD,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACzD,IAAI,WAAW,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACvC,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrE,OAAO,SAAS,KAAK,kBAAkB,IAAI,SAAS,KAAK,qCAAqC,CAAC;AAAA,CAC/F;AAED,KAAK,UAAU,QAAQ,CAAC,QAAkB,EAAE,QAAgB,EAAE,MAAmB,EAAuB;IACvG,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI;QACzB,MAAM,IAAI,4BAA4B,CAAC,kBAAkB,EAAE,CAAC,CAAC,mCAAmC,CAAC,CAAC,CAAC;IACpG,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;IACzC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,CAAC;QACJ,SAAS,CAAC;YACT,IAAI,MAAM,CAAC,OAAO;gBAAE,MAAM,IAAI,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,YAAY,CAAC,CAAC;YACvE,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YACjC,IAAI,IAAI,CAAC,IAAI;gBAAE,MAAM;YACrB,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;YAC/B,IAAI,KAAK,GAAG,QAAQ;gBACnB,MAAM,IAAI,4BAA4B,CACrC,oBAAoB,EACpB,CAAC,CAAC,yDAAyD,CAAC,CAC5D,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;IACF,CAAC;YAAS,CAAC;QACV,MAAM,CAAC,WAAW,EAAE,CAAC;IACtB,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;IACpC,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC;IAC5B,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb;AAeD,SAAS,cAAc,CAAC,KAAiB,EAAgD;IACxF,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACJ,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7E,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,4BAA4B,CAAC,kBAAkB,EAAE,CAAC,CAAC,yCAAyC,CAAC,CAAC,CAAC;IAC1G,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACtE,MAAM,IAAI,4BAA4B,CAAC,kBAAkB,EAAE,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC;IAC3F,MAAM,SAAS,GAAG,KAAoB,CAAC;IACvC,IAAI,OAAO,SAAS,CAAC,QAAQ,KAAK,QAAQ,IAAI,SAAS,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC;QAC7G,MAAM,IAAI,4BAA4B,CAAC,kBAAkB,EAAE,CAAC,CAAC,oCAAoC,CAAC,CAAC,CAAC;IACrG,OAAO,SAAS,CAAC,QAAQ,CAAC;AAAA,CAC1B;AAED,6FAA6F;AAC7F,MAAM,UAAU,6BAA6B,CAAC,OAAO,GAAmC,EAAE,EAA2B;IACpH,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC;IACpD,IAAI,OAAO,SAAS,KAAK,UAAU;QAClC,MAAM,IAAI,4BAA4B,CAAC,uBAAuB,EAAE,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC;IACjG,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,QAAQ,IAAI,uBAAuB,CAAC,CAAC;IAC7E,IACC,OAAO,CAAC,KAAK,KAAK,SAAS;QAC3B,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,IAAI,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAE9F,MAAM,IAAI,4BAA4B,CAAC,uBAAuB,EAAE,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC;IACrG,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,MAAM,SAAS,GAAG,eAAe,CAChC,OAAO,CAAC,gBAAgB,EACxB,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,CAClB,CAAC;IACF,MAAM,gBAAgB,GAAG,eAAe,CACvC,OAAO,CAAC,gBAAgB,EACxB,6BAA6B,EAC7B,qBAAqB,EACrB,kBAAkB,CAClB,CAAC;IACF,MAAM,eAAe,GAAG,eAAe,CACtC,OAAO,CAAC,eAAe,EACvB,4BAA4B,EAC5B,oBAAoB,EACpB,iBAAiB,CACjB,CAAC;IACF,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,oBAAoB,CAAC;IAClE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,YAAY,GAAG,CAAC,IAAI,YAAY,GAAG,gBAAgB;QAC7F,MAAM,IAAI,4BAA4B,CACrC,uBAAuB,EACvB,CAAC,CAAC,qDAAqD,EAAE,EAAE,GAAG,EAAE,gBAAgB,EAAE,CAAC,CACnF,CAAC;IACH,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,0BAA0B,CAAC;IAClE,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC;QAChF,MAAM,IAAI,4BAA4B,CAAC,uBAAuB,EAAE,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC;IAE5F,MAAM,uBAAuB,GAAG,KAAK,EACpC,GAAQ,EACR,OAAyC,EACzC,YAAqC,EACuC,EAAE,CAAC;QAC/E,IAAI,OAAO,GAAG,GAAG,CAAC;QAClB,KAAK,IAAI,QAAQ,GAAG,CAAC,GAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;YACxC,MAAM,OAAO,GAAG,aAAa,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;YACvD,IAAI,QAAkB,CAAC;YACvB,IAAI,CAAC;gBACJ,QAAQ,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE;oBAC9C,MAAM,EAAE,KAAK;oBACb,OAAO,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,OAAO,EAAE;oBAC/D,QAAQ,EAAE,QAAQ;oBAClB,MAAM,EAAE,OAAO,CAAC,MAAM;iBACtB,CAAC,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,OAAO,CAAC,OAAO,EAAE,CAAC;gBAClB,IAAI,OAAO,CAAC,QAAQ,EAAE;oBACrB,MAAM,IAAI,4BAA4B,CAAC,mBAAmB,EAAE,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC;gBAClG,IAAI,WAAW,CAAC,KAAK,CAAC;oBACrB,MAAM,IAAI,4BAA4B,CAAC,WAAW,EAAE,CAAC,CAAC,oCAAoC,CAAC,CAAC,CAAC;gBAC9F,MAAM,IAAI,4BAA4B,CAAC,gBAAgB,EAAE,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC;YAC5F,CAAC;YACD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;YACxE,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YAClD,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YACrD,OAAO,CAAC,OAAO,EAAE,CAAC;YAClB,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,IAAI,YAAY;gBAChD,MAAM,IAAI,4BAA4B,CAAC,gBAAgB,EAAE,CAAC,CAAC,sCAAsC,CAAC,CAAC,CAAC;YACrG,OAAO,GAAG,UAAU,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC7D,CAAC;IAAA,CACD,CAAC;IAEF,MAAM,iBAAiB,GAAG,KAAK,EAAE,KAIhC,EAAuC,EAAE,CAAC;QAC1C,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI;YACjC,MAAM,IAAI,4BAA4B,CAAC,WAAW,EAAE,CAAC,CAAC,oCAAoC,CAAC,CAAC,CAAC;QAC9F,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACpD,MAAM,aAAa,GAClB,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,CAAC;QACjE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,uBAAuB,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACnG,IAAI,CAAC;YACJ,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;gBACrD,MAAM,IAAI,4BAA4B,CAAC,mBAAmB,EAAE,CAAC,CAAC,2CAA2C,CAAC,CAAC,CAAC;YAC7G,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG;gBAClD,MAAM,IAAI,4BAA4B,CAAC,gBAAgB,EAAE,CAAC,CAAC,sCAAsC,CAAC,CAAC,CAAC;YACrG,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC;gBAC5B,MAAM,IAAI,4BAA4B,CAAC,kBAAkB,EAAE,CAAC,CAAC,oCAAoC,CAAC,CAAC,CAAC;YACrG,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAC5F,MAAM,OAAO,GAAG,yBAAyB,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;YAC9E,MAAM,IAAI,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC;YACzE,IACC,OAAO,KAAK,SAAS;gBACrB,IAAI,KAAK,SAAS;gBAClB,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ;gBAChC,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EACxB,CAAC;gBACF,MAAM,IAAI,4BAA4B,CACrC,mBAAmB,EACnB,CAAC,CAAC,oDAAoD,CAAC,CACvD,CAAC;YACH,CAAC;YACD,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC;YACtC,MAAM,SAAS,GACd,OAAO,cAAc,KAAK,QAAQ,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC;gBAC9D,CAAC,CAAC,gBAAgB,CAAC,cAAc,CAAC;gBAClC,CAAC,CAAC,SAAS,CAAC;YACd,IAAI,SAAS,KAAK,SAAS;gBAC1B,MAAM,IAAI,4BAA4B,CAAC,kBAAkB,EAAE,CAAC,CAAC,4CAA4C,CAAC,CAAC,CAAC;YAC7G,OAAO;gBACN,OAAO;gBACP,UAAU,EAAE,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE;gBAC/C,SAAS;gBACT,QAAQ,EAAE,IAAyC;aACnD,CAAC;QACH,CAAC;gBAAS,CAAC;YACV,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YACrD,OAAO,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC;IAAA,CACD,CAAC;IAEF,MAAM,YAAY,GAAG,KAAK,EAAE,KAA8D,EAAuB,EAAE,CAAC;QACnH,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI;YACjC,MAAM,IAAI,4BAA4B,CAAC,WAAW,EAAE,CAAC,CAAC,oCAAoC,CAAC,CAAC,CAAC;QAC9F,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,aAAa,GAClB,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,CAAC;QACjE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,uBAAuB,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACnG,IAAI,CAAC;YACJ,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG;gBAClD,MAAM,IAAI,4BAA4B,CAAC,gBAAgB,EAAE,CAAC,CAAC,sCAAsC,CAAC,CAAC,CAAC;YACrG,OAAO,MAAM,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAClE,CAAC;gBAAS,CAAC;YACV,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YACrD,OAAO,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC;IAAA,CACD,CAAC;IAEF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,iBAAiB,EAAE,YAAY,EAAE,CAAC;AAAA,CACjE","sourcesContent":["import { t } from \"../../core/i18n/index.ts\";\nimport { comparePluginVersionsV1 } from \"./catalog.ts\";\n\n/**\n * Minimal npm registry (packument) source for plugin package acquisition\n * (design `插件独立分发与启动装配设计.md` §4.2). It is a two-step protocol:\n * resolve the packument to pick one version, then fetch the tarball. It does\n * not implement `PluginRegistrySourceV1.list()`; the signed registry sources\n * keep serving private deployments unchanged.\n */\n\nconst DEFAULT_NPM_REGISTRY_V1 = \"https://registry.npmjs.org\";\nconst DEFAULT_TIMEOUT_MS_V1 = 15_000;\nconst MAX_TIMEOUT_MS_V1 = 120_000;\nconst DEFAULT_MAX_RESPONSE_BYTES_V1 = 8 * 1024 * 1024;\nconst MAX_RESPONSE_BYTES_V1 = 16 * 1024 * 1024;\nconst DEFAULT_MAX_TARBALL_BYTES_V1 = 128 * 1024 * 1024;\nconst MAX_TARBALL_BYTES_V1 = 512 * 1024 * 1024;\nconst DEFAULT_REDIRECTS_V1 = 3;\nconst MAX_REDIRECTS_V1 = 5;\nconst REDIRECT_STATUS = new Set([301, 302, 303, 307, 308]);\n\nexport type NodeNpmRegistrySourceErrorCodeV1 =\n\t| \"cancelled\"\n\t| \"invalid_configuration\"\n\t| \"request_failed\"\n\t| \"request_timed_out\"\n\t| \"invalid_response\"\n\t| \"response_too_large\"\n\t| \"package_not_found\"\n\t| \"version_not_found\"\n\t| \"integrity_unsupported\";\n\nexport class NodeNpmRegistrySourceErrorV1 extends Error {\n\treadonly code: NodeNpmRegistrySourceErrorCodeV1;\n\n\tconstructor(code: NodeNpmRegistrySourceErrorCodeV1, message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"NodeNpmRegistrySourceErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\n/** SRI integrity as hex plus its algorithm, aligned with the install host digest format. */\nexport interface NodeNpmIntegrityV1 {\n\treadonly algorithm: \"sha256\" | \"sha512\";\n\treadonly hex: string;\n}\n\nexport interface NodeNpmPackageResolutionV1 {\n\treadonly version: string;\n\treadonly tarballUrl: string;\n\treadonly integrity: NodeNpmIntegrityV1;\n\t/** Raw `dist` fields of the selected version. */\n\treadonly distInfo: Readonly<Record<string, unknown>>;\n}\n\nexport interface NodeNpmRegistrySourceOptionsV1 {\n\t/** Bare http(s) registry origin; defaults to the npm public registry. */\n\treadonly registry?: string;\n\t/** Bearer token for private registries. */\n\treadonly token?: string;\n\t/** Real fetch or a deterministic test replacement. */\n\treadonly fetch?: typeof globalThis.fetch;\n\treadonly requestTimeoutMs?: number;\n\treadonly maxResponseBytes?: number;\n\treadonly maxTarballBytes?: number;\n\treadonly maxRedirects?: number;\n\treadonly userAgent?: string;\n}\n\nexport interface NodeNpmRegistrySourceV1 {\n\treadonly version: 1;\n\t/** Sanitized bare registry origin (no credentials, path, query, or fragment). */\n\treadonly registry: string;\n\treadonly resolveNpmPackage: (input: {\n\t\treadonly name: string;\n\t\treadonly range?: string;\n\t\treadonly signal?: AbortSignal;\n\t}) => Promise<NodeNpmPackageResolutionV1>;\n\treadonly fetchTarball: (input: { readonly url: string; readonly signal?: AbortSignal }) => Promise<Uint8Array>;\n}\n\n/** Convert an npm SRI string (`sha512-<base64>`, `sha256-<base64>`) to hex form. */\nexport function sriToIntegrityV1(sri: string): NodeNpmIntegrityV1 {\n\tconst match = /^(sha512|sha256)-([A-Za-z0-9+/]+={0,2})$/u.exec(sri.trim());\n\tif (match === null)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"integrity_unsupported\", t(\"npm integrity algorithm is unsupported\"));\n\tconst algorithm = match[1] as \"sha512\" | \"sha256\";\n\tlet raw: Buffer;\n\ttry {\n\t\traw = Buffer.from(match[2]!, \"base64\");\n\t} catch {\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"integrity_unsupported\", t(\"npm integrity encoding is invalid\"));\n\t}\n\tif ((algorithm === \"sha256\" && raw.byteLength !== 32) || (algorithm === \"sha512\" && raw.byteLength !== 64))\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"integrity_unsupported\", t(\"npm integrity length is invalid\"));\n\tconst hex = raw.toString(\"hex\").toLowerCase();\n\tif (hex.length === 0) throw new NodeNpmRegistrySourceErrorV1(\"integrity_unsupported\", t(\"npm integrity is invalid\"));\n\treturn { algorithm, hex };\n}\n\nfunction parseVersionTriple(value: string): readonly [number, number, number] | undefined {\n\tconst match = /^(\\d+)\\.(\\d+)\\.(\\d+)/u.exec(value.replace(/^[vV]/u, \"\"));\n\tif (match === null) return undefined;\n\tconst major = Number.parseInt(match[1]!, 10);\n\tconst minor = Number.parseInt(match[2]!, 10);\n\tconst patch = Number.parseInt(match[3]!, 10);\n\tif (!Number.isSafeInteger(major) || !Number.isSafeInteger(minor) || !Number.isSafeInteger(patch)) return undefined;\n\treturn [major, minor, patch] as const;\n}\n\nfunction plainVersion(value: string): string {\n\treturn value.replace(/^[vV]/u, \"\");\n}\n\n/**\n * Select the highest version satisfying a minimal range subset using the\n * ecosystem comparator (`comparePluginVersionsV1`): `undefined`/`latest` →\n * highest; `x.y.z` → exact full match (prerelease suffix included);\n * `^x.y.z` → >= x.y.z and < (x+1).0.0; `~x.y.z` → >= x.y.z and\n * < x.(y+1).0. Bounds use the comparator ordering (e.g. `1.0.0-alpha`\n * sorts below `1.0.0`).\n */\nexport function selectNpmPackageVersionV1(versions: readonly string[], range?: string): string | undefined {\n\tif (!Array.isArray(versions)) return undefined;\n\tlet candidates = versions.filter((value) => typeof value === \"string\" && parseVersionTriple(value) !== undefined);\n\tif (candidates.length === 0) return undefined;\n\tif (range === undefined || range === \"latest\") {\n\t\treturn candidates.reduce((left, right) => (comparePluginVersionsV1(right, left) > 0 ? right : left));\n\t}\n\tconst exact = plainVersion(range.replace(/^[=~^]/u, \"\"));\n\tif (!range.startsWith(\"^\") && !range.startsWith(\"~\"))\n\t\treturn candidates.find((value) => plainVersion(value) === exact);\n\tconst bound = parseVersionTriple(exact);\n\tif (bound === undefined) return undefined;\n\tconst [major, minor] = bound;\n\tconst upper = range.startsWith(\"^\") ? `${major + 1}.0.0` : `${major}.${minor + 1}.0`;\n\tcandidates = candidates.filter(\n\t\t(value) => comparePluginVersionsV1(value, exact) >= 0 && comparePluginVersionsV1(value, upper) < 0,\n\t);\n\tif (candidates.length === 0) return undefined;\n\treturn candidates.reduce((left, right) => (comparePluginVersionsV1(right, left) > 0 ? right : left));\n}\n\nfunction boundedPositive(value: number | undefined, fallback: number, maximum: number, label: string): number {\n\tconst result = value ?? fallback;\n\tif (!Number.isSafeInteger(result) || result <= 0 || result > maximum)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"{label} must be a positive integer at most {maximum}\", { label, maximum }),\n\t\t);\n\treturn result;\n}\n\nfunction registryOrigin(value: string): string {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"npm registry origin is invalid\"));\n\t}\n\tif (\n\t\t(parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") ||\n\t\tparsed.username !== \"\" ||\n\t\tparsed.password !== \"\"\n\t)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"npm registry origin must be http(s) without credentials\"),\n\t\t);\n\tif (parsed.pathname !== \"/\" || parsed.search !== \"\" || parsed.hash !== \"\")\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"npm registry origin must not include a path, query, or fragment\"),\n\t\t);\n\treturn parsed.origin;\n}\n\nfunction packumentUrl(registryOriginValue: string, name: string): URL {\n\tconst scopeAt = name.indexOf(\"/\");\n\tif (name.startsWith(\"@\") && scopeAt > 0) {\n\t\t// npm registry convention keeps the leading scope literal and percent\n\t\t// encodes the rest of the name, including the separating slash.\n\t\tconst scope = name.slice(0, scopeAt);\n\t\tconst packageName = name.slice(scopeAt + 1);\n\t\treturn new URL(`${registryOriginValue}/${scope}%2F${encodeURIComponent(packageName)}`);\n\t}\n\tif (scopeAt >= 0) throw new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"npm package name is invalid\"));\n\treturn new URL(`${registryOriginValue}/${encodeURIComponent(name)}`);\n}\n\nfunction tarballUrl(value: string): URL {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm tarball URL is invalid\"));\n\t}\n\tif (\n\t\t(parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") ||\n\t\tparsed.username !== \"\" ||\n\t\tparsed.password !== \"\"\n\t)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_response\",\n\t\t\tt(\"npm tarball URL must use http(s) without credentials\"),\n\t\t);\n\tif (parsed.hash !== \"\")\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm tarball URL must not include a fragment\"));\n\treturn parsed;\n}\n\nfunction isAbortLike(error: unknown): boolean {\n\treturn error instanceof Error && (error.name === \"AbortError\" || error.name === \"AbortSignalError\");\n}\n\ninterface RequestSignal {\n\treadonly signal: AbortSignal;\n\treadonly timedOut: () => boolean;\n\treadonly cleanup: () => void;\n}\n\nfunction requestSignal(parent: AbortSignal | undefined, timeoutMs: number): RequestSignal {\n\tconst controller = new AbortController();\n\tlet timedOut = false;\n\tconst abort = () => controller.abort(parent?.reason);\n\tif (parent?.aborted === true) abort();\n\telse parent?.addEventListener(\"abort\", abort, { once: true });\n\tconst timeout = setTimeout(() => {\n\t\ttimedOut = true;\n\t\tcontroller.abort();\n\t}, timeoutMs);\n\treturn {\n\t\tsignal: controller.signal,\n\t\ttimedOut: () => timedOut,\n\t\tcleanup: () => {\n\t\t\tclearTimeout(timeout);\n\t\t\tparent?.removeEventListener(\"abort\", abort);\n\t\t},\n\t};\n}\n\nfunction isJsonResponse(response: Response): boolean {\n\tconst contentType = response.headers.get(\"content-type\");\n\tif (contentType === null) return false;\n\tconst mediaType = contentType.split(\";\", 1)[0]?.trim().toLowerCase();\n\treturn mediaType === \"application/json\" || mediaType === \"application/vnd.npm.install-v1+json\";\n}\n\nasync function readBody(response: Response, maxBytes: number, signal: AbortSignal): Promise<Uint8Array> {\n\tif (response.body === null)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm registry response has no body\"));\n\tconst reader = response.body.getReader();\n\tconst chunks: Uint8Array[] = [];\n\tlet total = 0;\n\ttry {\n\t\tfor (;;) {\n\t\t\tif (signal.aborted) throw new DOMException(t(\"aborted\"), \"AbortError\");\n\t\t\tconst item = await reader.read();\n\t\t\tif (item.done) break;\n\t\t\ttotal += item.value.byteLength;\n\t\t\tif (total > maxBytes)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\t\t\"response_too_large\",\n\t\t\t\t\tt(\"npm registry response exceeds the configured size limit\"),\n\t\t\t\t);\n\t\t\tchunks.push(item.value);\n\t\t}\n\t} finally {\n\t\treader.releaseLock();\n\t}\n\tconst bytes = new Uint8Array(total);\n\tlet offset = 0;\n\tfor (const chunk of chunks) {\n\t\tbytes.set(chunk, offset);\n\t\toffset += chunk.byteLength;\n\t}\n\treturn bytes;\n}\n\ninterface PackumentVersionDistV1 {\n\treadonly tarball?: unknown;\n\treadonly integrity?: unknown;\n}\n\ninterface PackumentVersionV1 {\n\treadonly dist?: PackumentVersionDistV1;\n}\n\ninterface PackumentV1 {\n\treadonly versions?: Readonly<Record<string, PackumentVersionV1>>;\n}\n\nfunction parsePackument(bytes: Uint8Array): Readonly<Record<string, PackumentVersionV1>> {\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes));\n\t} catch {\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm registry response is not valid JSON\"));\n\t}\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value))\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm packument is invalid\"));\n\tconst packument = value as PackumentV1;\n\tif (typeof packument.versions !== \"object\" || packument.versions === null || Array.isArray(packument.versions))\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm packument has no version table\"));\n\treturn packument.versions;\n}\n\n/** Create a bounded npm registry reader. Version selection uses the ecosystem comparator. */\nexport function createNodeNpmRegistrySourceV1(options: NodeNpmRegistrySourceOptionsV1 = {}): NodeNpmRegistrySourceV1 {\n\tconst transport = options.fetch ?? globalThis.fetch;\n\tif (typeof transport !== \"function\")\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"Node fetch is unavailable\"));\n\tconst registry = registryOrigin(options.registry ?? DEFAULT_NPM_REGISTRY_V1);\n\tif (\n\t\toptions.token !== undefined &&\n\t\t(options.token.length === 0 || options.token.length > 4096 || /[\\r\\n\\s]/u.test(options.token))\n\t)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"npm registry token is invalid\"));\n\tconst token = options.token;\n\tconst timeoutMs = boundedPositive(\n\t\toptions.requestTimeoutMs,\n\t\tDEFAULT_TIMEOUT_MS_V1,\n\t\tMAX_TIMEOUT_MS_V1,\n\t\t\"requestTimeoutMs\",\n\t);\n\tconst maxResponseBytes = boundedPositive(\n\t\toptions.maxResponseBytes,\n\t\tDEFAULT_MAX_RESPONSE_BYTES_V1,\n\t\tMAX_RESPONSE_BYTES_V1,\n\t\t\"maxResponseBytes\",\n\t);\n\tconst maxTarballBytes = boundedPositive(\n\t\toptions.maxTarballBytes,\n\t\tDEFAULT_MAX_TARBALL_BYTES_V1,\n\t\tMAX_TARBALL_BYTES_V1,\n\t\t\"maxTarballBytes\",\n\t);\n\tconst maxRedirects = options.maxRedirects ?? DEFAULT_REDIRECTS_V1;\n\tif (!Number.isSafeInteger(maxRedirects) || maxRedirects < 0 || maxRedirects > MAX_REDIRECTS_V1)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"maxRedirects must be an integer between 0 and {max}\", { max: MAX_REDIRECTS_V1 }),\n\t\t);\n\tconst userAgent = options.userAgent ?? \"agent-forge-plugin-npm/1\";\n\tif (userAgent.length === 0 || userAgent.length > 256 || /[\\r\\n]/u.test(userAgent))\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"userAgent is invalid\"));\n\n\tconst fetchFollowingRedirects = async (\n\t\turl: URL,\n\t\theaders: Readonly<Record<string, string>>,\n\t\tparentSignal: AbortSignal | undefined,\n\t): Promise<{ readonly response: Response; readonly request: RequestSignal }> => {\n\t\tlet current = url;\n\t\tfor (let redirect = 0; ; redirect += 1) {\n\t\t\tconst request = requestSignal(parentSignal, timeoutMs);\n\t\t\tlet response: Response;\n\t\t\ttry {\n\t\t\t\tresponse = await transport(current.toString(), {\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\theaders: { accept: \"*/*\", \"user-agent\": userAgent, ...headers },\n\t\t\t\t\tredirect: \"manual\",\n\t\t\t\t\tsignal: request.signal,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\trequest.cleanup();\n\t\t\t\tif (request.timedOut())\n\t\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_timed_out\", t(\"npm registry request timed out\"));\n\t\t\t\tif (isAbortLike(error))\n\t\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"cancelled\", t(\"npm registry request was cancelled\"));\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_failed\", t(\"npm registry request failed\"));\n\t\t\t}\n\t\t\tif (!REDIRECT_STATUS.has(response.status)) return { response, request };\n\t\t\tconst location = response.headers.get(\"location\");\n\t\t\tawait response.body?.cancel().catch(() => undefined);\n\t\t\trequest.cleanup();\n\t\t\tif (location === null || redirect >= maxRedirects)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_failed\", t(\"npm registry redirect limit exceeded\"));\n\t\t\tcurrent = tarballUrl(new URL(location, current).toString());\n\t\t}\n\t};\n\n\tconst resolveNpmPackage = async (input: {\n\t\treadonly name: string;\n\t\treadonly range?: string;\n\t\treadonly signal?: AbortSignal;\n\t}): Promise<NodeNpmPackageResolutionV1> => {\n\t\tif (input.signal?.aborted === true)\n\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"cancelled\", t(\"npm registry request was cancelled\"));\n\t\tconst endpoint = packumentUrl(registry, input.name);\n\t\tconst authorization: Readonly<Record<string, string>> =\n\t\t\ttoken === undefined ? {} : { authorization: `Bearer ${token}` };\n\t\tconst { response, request } = await fetchFollowingRedirects(endpoint, authorization, input.signal);\n\t\ttry {\n\t\t\tif (response.status === 404 || response.status === 403)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"package_not_found\", t(\"npm package was not found on the registry\"));\n\t\t\tif (response.status < 200 || response.status >= 300)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_failed\", t(\"npm registry request did not succeed\"));\n\t\t\tif (!isJsonResponse(response))\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm registry response must be JSON\"));\n\t\t\tconst versions = parsePackument(await readBody(response, maxResponseBytes, request.signal));\n\t\t\tconst version = selectNpmPackageVersionV1(Object.keys(versions), input.range);\n\t\t\tconst dist = version === undefined ? undefined : versions[version]?.dist;\n\t\t\tif (\n\t\t\t\tversion === undefined ||\n\t\t\t\tdist === undefined ||\n\t\t\t\ttypeof dist.tarball !== \"string\" ||\n\t\t\t\tdist.tarball.length === 0\n\t\t\t) {\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\t\t\"version_not_found\",\n\t\t\t\t\tt(\"No npm package version matches the requested range\"),\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst integrityValue = dist.integrity;\n\t\t\tconst integrity =\n\t\t\t\ttypeof integrityValue === \"string\" && integrityValue.length > 0\n\t\t\t\t\t? sriToIntegrityV1(integrityValue)\n\t\t\t\t\t: undefined;\n\t\t\tif (integrity === undefined)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm package version has no integrity field\"));\n\t\t\treturn {\n\t\t\t\tversion,\n\t\t\t\ttarballUrl: tarballUrl(dist.tarball).toString(),\n\t\t\t\tintegrity,\n\t\t\t\tdistInfo: dist as Readonly<Record<string, unknown>>,\n\t\t\t};\n\t\t} finally {\n\t\t\tawait response.body?.cancel().catch(() => undefined);\n\t\t\trequest.cleanup();\n\t\t}\n\t};\n\n\tconst fetchTarball = async (input: { readonly url: string; readonly signal?: AbortSignal }): Promise<Uint8Array> => {\n\t\tif (input.signal?.aborted === true)\n\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"cancelled\", t(\"npm tarball download was cancelled\"));\n\t\tconst endpoint = tarballUrl(input.url);\n\t\tconst authorization: Readonly<Record<string, string>> =\n\t\t\ttoken === undefined ? {} : { authorization: `Bearer ${token}` };\n\t\tconst { response, request } = await fetchFollowingRedirects(endpoint, authorization, input.signal);\n\t\ttry {\n\t\t\tif (response.status < 200 || response.status >= 300)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_failed\", t(\"npm tarball download did not succeed\"));\n\t\t\treturn await readBody(response, maxTarballBytes, request.signal);\n\t\t} finally {\n\t\t\tawait response.body?.cancel().catch(() => undefined);\n\t\t\trequest.cleanup();\n\t\t}\n\t};\n\n\treturn { version: 1, registry, resolveNpmPackage, fetchTarball };\n}\n"]}
1
+ {"version":3,"file":"node-npm-registry-source.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-npm-registry-source.ts"],"names":[],"mappings":"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","sourcesContent":["import { t } from \"../../core/i18n/index.ts\";\nimport { comparePluginVersionsV1 } from \"./catalog.ts\";\n\n/**\n * Minimal npm registry (packument) source for plugin package acquisition\n * (design `插件独立分发与启动装配设计.md` §4.2). It is a two-step protocol:\n * resolve the packument to pick one version, then fetch the tarball. It does\n * not implement `PluginRegistrySourceV1.list()`; the signed registry sources\n * keep serving private deployments unchanged.\n */\n\nconst DEFAULT_NPM_REGISTRY_V1 = \"https://registry.npmjs.org\";\nconst DEFAULT_TIMEOUT_MS_V1 = 15_000;\nconst MAX_TIMEOUT_MS_V1 = 120_000;\nconst DEFAULT_MAX_RESPONSE_BYTES_V1 = 8 * 1024 * 1024;\nconst MAX_RESPONSE_BYTES_V1 = 16 * 1024 * 1024;\nconst DEFAULT_MAX_TARBALL_BYTES_V1 = 128 * 1024 * 1024;\nconst MAX_TARBALL_BYTES_V1 = 512 * 1024 * 1024;\nconst DEFAULT_REDIRECTS_V1 = 3;\nconst MAX_REDIRECTS_V1 = 5;\nconst REDIRECT_STATUS = new Set([301, 302, 303, 307, 308]);\n\nexport type NodeNpmRegistrySourceErrorCodeV1 =\n\t| \"cancelled\"\n\t| \"invalid_configuration\"\n\t| \"request_failed\"\n\t| \"request_timed_out\"\n\t| \"invalid_response\"\n\t| \"response_too_large\"\n\t| \"package_not_found\"\n\t| \"version_not_found\"\n\t| \"integrity_unsupported\"\n\t| \"rate_limited\";\n\nexport class NodeNpmRegistrySourceErrorV1 extends Error {\n\treadonly code: NodeNpmRegistrySourceErrorCodeV1;\n\t/** `Retry-After` seconds advertised by the registry; present only for `rate_limited`. */\n\treadonly retryAfterSeconds?: number;\n\n\tconstructor(\n\t\tcode: NodeNpmRegistrySourceErrorCodeV1,\n\t\tmessage: string,\n\t\toptions?: { readonly cause?: unknown; readonly retryAfterSeconds?: number },\n\t) {\n\t\tsuper(message, options?.cause === undefined ? undefined : { cause: options.cause });\n\t\tthis.name = \"NodeNpmRegistrySourceErrorV1\";\n\t\tthis.code = code;\n\t\tif (options?.retryAfterSeconds !== undefined) this.retryAfterSeconds = options.retryAfterSeconds;\n\t}\n}\n\n/** SRI integrity as hex plus its algorithm, aligned with the install host digest format. */\nexport interface NodeNpmIntegrityV1 {\n\treadonly algorithm: \"sha256\" | \"sha512\";\n\treadonly hex: string;\n}\n\nexport interface NodeNpmPackageResolutionV1 {\n\treadonly version: string;\n\treadonly tarballUrl: string;\n\treadonly integrity: NodeNpmIntegrityV1;\n\t/** Raw `dist` fields of the selected version. */\n\treadonly distInfo: Readonly<Record<string, unknown>>;\n}\n\nexport interface NodeNpmRegistrySourceOptionsV1 {\n\t/** Bare http(s) registry origin; defaults to the npm public registry. */\n\treadonly registry?: string;\n\t/** Bearer token for private registries. */\n\treadonly token?: string;\n\t/** Real fetch or a deterministic test replacement. */\n\treadonly fetch?: typeof globalThis.fetch;\n\treadonly requestTimeoutMs?: number;\n\treadonly maxResponseBytes?: number;\n\treadonly maxTarballBytes?: number;\n\treadonly maxRedirects?: number;\n\treadonly userAgent?: string;\n}\n\nexport interface NodeNpmRegistrySourceV1 {\n\treadonly version: 1;\n\t/** Sanitized bare registry origin (no credentials, path, query, or fragment). */\n\treadonly registry: string;\n\treadonly resolveNpmPackage: (input: {\n\t\treadonly name: string;\n\t\treadonly range?: string;\n\t\treadonly signal?: AbortSignal;\n\t}) => Promise<NodeNpmPackageResolutionV1>;\n\treadonly fetchTarball: (input: { readonly url: string; readonly signal?: AbortSignal }) => Promise<Uint8Array>;\n}\n\n/** Convert an npm SRI string (`sha512-<base64>`, `sha256-<base64>`) to hex form. */\nexport function sriToIntegrityV1(sri: string): NodeNpmIntegrityV1 {\n\tconst match = /^(sha512|sha256)-([A-Za-z0-9+/]+={0,2})$/u.exec(sri.trim());\n\tif (match === null)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"integrity_unsupported\", t(\"npm integrity algorithm is unsupported\"));\n\tconst algorithm = match[1] as \"sha512\" | \"sha256\";\n\tlet raw: Buffer;\n\ttry {\n\t\traw = Buffer.from(match[2]!, \"base64\");\n\t} catch {\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"integrity_unsupported\", t(\"npm integrity encoding is invalid\"));\n\t}\n\tif ((algorithm === \"sha256\" && raw.byteLength !== 32) || (algorithm === \"sha512\" && raw.byteLength !== 64))\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"integrity_unsupported\", t(\"npm integrity length is invalid\"));\n\tconst hex = raw.toString(\"hex\").toLowerCase();\n\tif (hex.length === 0) throw new NodeNpmRegistrySourceErrorV1(\"integrity_unsupported\", t(\"npm integrity is invalid\"));\n\treturn { algorithm, hex };\n}\n\nfunction parseVersionTriple(value: string): readonly [number, number, number] | undefined {\n\tconst match = /^(\\d+)\\.(\\d+)\\.(\\d+)/u.exec(value.replace(/^[vV]/u, \"\"));\n\tif (match === null) return undefined;\n\tconst major = Number.parseInt(match[1]!, 10);\n\tconst minor = Number.parseInt(match[2]!, 10);\n\tconst patch = Number.parseInt(match[3]!, 10);\n\tif (!Number.isSafeInteger(major) || !Number.isSafeInteger(minor) || !Number.isSafeInteger(patch)) return undefined;\n\treturn [major, minor, patch] as const;\n}\n\nfunction plainVersion(value: string): string {\n\treturn value.replace(/^[vV]/u, \"\");\n}\n\n/**\n * Select the highest version satisfying a minimal range subset using the\n * ecosystem comparator (`comparePluginVersionsV1`): `undefined`/`latest` →\n * highest; `x.y.z` → exact full match (prerelease suffix included);\n * `^x.y.z` → >= x.y.z and < (x+1).0.0; `~x.y.z` → >= x.y.z and\n * < x.(y+1).0. Bounds use the comparator ordering (e.g. `1.0.0-alpha`\n * sorts below `1.0.0`).\n */\nexport function selectNpmPackageVersionV1(versions: readonly string[], range?: string): string | undefined {\n\tif (!Array.isArray(versions)) return undefined;\n\tlet candidates = versions.filter((value) => typeof value === \"string\" && parseVersionTriple(value) !== undefined);\n\tif (candidates.length === 0) return undefined;\n\tif (range === undefined || range === \"latest\") {\n\t\treturn candidates.reduce((left, right) => (comparePluginVersionsV1(right, left) > 0 ? right : left));\n\t}\n\tconst exact = plainVersion(range.replace(/^[=~^]/u, \"\"));\n\tif (!range.startsWith(\"^\") && !range.startsWith(\"~\"))\n\t\treturn candidates.find((value) => plainVersion(value) === exact);\n\tconst bound = parseVersionTriple(exact);\n\tif (bound === undefined) return undefined;\n\tconst [major, minor] = bound;\n\tconst upper = range.startsWith(\"^\") ? `${major + 1}.0.0` : `${major}.${minor + 1}.0`;\n\tcandidates = candidates.filter(\n\t\t(value) => comparePluginVersionsV1(value, exact) >= 0 && comparePluginVersionsV1(value, upper) < 0,\n\t);\n\tif (candidates.length === 0) return undefined;\n\treturn candidates.reduce((left, right) => (comparePluginVersionsV1(right, left) > 0 ? right : left));\n}\n\nfunction boundedPositive(value: number | undefined, fallback: number, maximum: number, label: string): number {\n\tconst result = value ?? fallback;\n\tif (!Number.isSafeInteger(result) || result <= 0 || result > maximum)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"{label} must be a positive integer at most {maximum}\", { label, maximum }),\n\t\t);\n\treturn result;\n}\n\nfunction registryOrigin(value: string): string {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"npm registry origin is invalid\"));\n\t}\n\tif (\n\t\t(parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") ||\n\t\tparsed.username !== \"\" ||\n\t\tparsed.password !== \"\"\n\t)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"npm registry origin must be http(s) without credentials\"),\n\t\t);\n\tif (parsed.pathname !== \"/\" || parsed.search !== \"\" || parsed.hash !== \"\")\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"npm registry origin must not include a path, query, or fragment\"),\n\t\t);\n\treturn parsed.origin;\n}\n\nfunction packumentUrl(registryOriginValue: string, name: string): URL {\n\tconst scopeAt = name.indexOf(\"/\");\n\tif (name.startsWith(\"@\") && scopeAt > 0) {\n\t\t// npm registry convention keeps the leading scope literal and percent\n\t\t// encodes the rest of the name, including the separating slash.\n\t\tconst scope = name.slice(0, scopeAt);\n\t\tconst packageName = name.slice(scopeAt + 1);\n\t\treturn new URL(`${registryOriginValue}/${scope}%2F${encodeURIComponent(packageName)}`);\n\t}\n\tif (scopeAt >= 0) throw new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"npm package name is invalid\"));\n\treturn new URL(`${registryOriginValue}/${encodeURIComponent(name)}`);\n}\n\nfunction tarballUrl(value: string): URL {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm tarball URL is invalid\"));\n\t}\n\tif (\n\t\t(parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") ||\n\t\tparsed.username !== \"\" ||\n\t\tparsed.password !== \"\"\n\t)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_response\",\n\t\t\tt(\"npm tarball URL must use http(s) without credentials\"),\n\t\t);\n\tif (parsed.hash !== \"\")\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm tarball URL must not include a fragment\"));\n\treturn parsed;\n}\n\nfunction isAbortLike(error: unknown): boolean {\n\treturn error instanceof Error && (error.name === \"AbortError\" || error.name === \"AbortSignalError\");\n}\n\ninterface RequestSignal {\n\treadonly signal: AbortSignal;\n\treadonly timedOut: () => boolean;\n\treadonly cleanup: () => void;\n}\n\nfunction requestSignal(parent: AbortSignal | undefined, timeoutMs: number): RequestSignal {\n\tconst controller = new AbortController();\n\tlet timedOut = false;\n\tconst abort = () => controller.abort(parent?.reason);\n\tif (parent?.aborted === true) abort();\n\telse parent?.addEventListener(\"abort\", abort, { once: true });\n\tconst timeout = setTimeout(() => {\n\t\ttimedOut = true;\n\t\tcontroller.abort();\n\t}, timeoutMs);\n\treturn {\n\t\tsignal: controller.signal,\n\t\ttimedOut: () => timedOut,\n\t\tcleanup: () => {\n\t\t\tclearTimeout(timeout);\n\t\t\tparent?.removeEventListener(\"abort\", abort);\n\t\t},\n\t};\n}\n\nfunction isJsonResponse(response: Response): boolean {\n\tconst contentType = response.headers.get(\"content-type\");\n\tif (contentType === null) return false;\n\tconst mediaType = contentType.split(\";\", 1)[0]?.trim().toLowerCase();\n\treturn mediaType === \"application/json\" || mediaType === \"application/vnd.npm.install-v1+json\";\n}\n\n/**\n * Rate-limit verdict for 429/403 responses, isomorphic with the release\n * source: any 429, and a 403 whose `X-RateLimit-Remaining` is exactly `0`.\n * `Retry-After` passes through as whole seconds when present and integer-like;\n * absent or malformed headers stay absent.\n */\nfunction rateLimitState(response: Response): { readonly limited: boolean; readonly retryAfterSeconds?: number } {\n\tconst limited =\n\t\tresponse.status === 429 || (response.status === 403 && response.headers.get(\"x-ratelimit-remaining\") === \"0\");\n\tif (!limited) return { limited: false };\n\tconst retryAfter = response.headers.get(\"retry-after\");\n\tconst seconds = retryAfter === null ? Number.NaN : Number.parseInt(retryAfter, 10);\n\tif (!Number.isSafeInteger(seconds) || seconds < 0) return { limited: true };\n\treturn { limited: true, retryAfterSeconds: seconds };\n}\n\nfunction rateLimitError(limit: { readonly retryAfterSeconds?: number }): NodeNpmRegistrySourceErrorV1 {\n\tconst message =\n\t\tlimit.retryAfterSeconds === undefined\n\t\t\t? t(\"npm registry rate limit was exceeded\")\n\t\t\t: `${t(\"npm registry rate limit was exceeded\")} (retry after ${limit.retryAfterSeconds}s)`;\n\treturn new NodeNpmRegistrySourceErrorV1(\"rate_limited\", message, {\n\t\t...(limit.retryAfterSeconds === undefined ? {} : { retryAfterSeconds: limit.retryAfterSeconds }),\n\t});\n}\n\n/**\n * Read a bounded body. Aborts are classified by their owner: the module's own\n * timeout timer surfaces as `request_timed_out`, an externally cancelled\n * signal as `cancelled` — the raw AbortError would otherwise fall through to\n * the generic download failure and hide the real cause.\n */\nasync function readBody(response: Response, maxBytes: number, request: RequestSignal): Promise<Uint8Array> {\n\tif (response.body === null)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm registry response has no body\"));\n\tconst reader = response.body.getReader();\n\tconst chunks: Uint8Array[] = [];\n\tlet total = 0;\n\tconst abortError = (): NodeNpmRegistrySourceErrorV1 =>\n\t\trequest.timedOut()\n\t\t\t? new NodeNpmRegistrySourceErrorV1(\"request_timed_out\", t(\"npm registry request timed out\"))\n\t\t\t: new NodeNpmRegistrySourceErrorV1(\"cancelled\", t(\"npm registry request was cancelled\"));\n\ttry {\n\t\tfor (;;) {\n\t\t\tif (request.signal.aborted) throw abortError();\n\t\t\tlet item: Awaited<ReturnType<typeof reader.read>>;\n\t\t\ttry {\n\t\t\t\titem = await reader.read();\n\t\t\t} catch (error) {\n\t\t\t\tif (request.signal.aborted) throw abortError();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tif (item.done) break;\n\t\t\ttotal += item.value.byteLength;\n\t\t\tif (total > maxBytes)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\t\t\"response_too_large\",\n\t\t\t\t\tt(\"npm registry response exceeds the configured size limit\"),\n\t\t\t\t);\n\t\t\tchunks.push(item.value);\n\t\t}\n\t} finally {\n\t\treader.releaseLock();\n\t}\n\tconst bytes = new Uint8Array(total);\n\tlet offset = 0;\n\tfor (const chunk of chunks) {\n\t\tbytes.set(chunk, offset);\n\t\toffset += chunk.byteLength;\n\t}\n\treturn bytes;\n}\n\ninterface PackumentVersionDistV1 {\n\treadonly tarball?: unknown;\n\treadonly integrity?: unknown;\n}\n\ninterface PackumentVersionV1 {\n\treadonly dist?: PackumentVersionDistV1;\n}\n\ninterface PackumentV1 {\n\treadonly versions?: Readonly<Record<string, PackumentVersionV1>>;\n}\n\nfunction parsePackument(bytes: Uint8Array): Readonly<Record<string, PackumentVersionV1>> {\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes));\n\t} catch {\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm registry response is not valid JSON\"));\n\t}\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value))\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm packument is invalid\"));\n\tconst packument = value as PackumentV1;\n\tif (typeof packument.versions !== \"object\" || packument.versions === null || Array.isArray(packument.versions))\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm packument has no version table\"));\n\treturn packument.versions;\n}\n\n/** Create a bounded npm registry reader. Version selection uses the ecosystem comparator. */\nexport function createNodeNpmRegistrySourceV1(options: NodeNpmRegistrySourceOptionsV1 = {}): NodeNpmRegistrySourceV1 {\n\tconst transport = options.fetch ?? globalThis.fetch;\n\tif (typeof transport !== \"function\")\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"Node fetch is unavailable\"));\n\tconst registry = registryOrigin(options.registry ?? DEFAULT_NPM_REGISTRY_V1);\n\tif (\n\t\toptions.token !== undefined &&\n\t\t(options.token.length === 0 || options.token.length > 4096 || /[\\r\\n\\s]/u.test(options.token))\n\t)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"npm registry token is invalid\"));\n\tconst token = options.token;\n\tconst timeoutMs = boundedPositive(\n\t\toptions.requestTimeoutMs,\n\t\tDEFAULT_TIMEOUT_MS_V1,\n\t\tMAX_TIMEOUT_MS_V1,\n\t\t\"requestTimeoutMs\",\n\t);\n\tconst maxResponseBytes = boundedPositive(\n\t\toptions.maxResponseBytes,\n\t\tDEFAULT_MAX_RESPONSE_BYTES_V1,\n\t\tMAX_RESPONSE_BYTES_V1,\n\t\t\"maxResponseBytes\",\n\t);\n\tconst maxTarballBytes = boundedPositive(\n\t\toptions.maxTarballBytes,\n\t\tDEFAULT_MAX_TARBALL_BYTES_V1,\n\t\tMAX_TARBALL_BYTES_V1,\n\t\t\"maxTarballBytes\",\n\t);\n\tconst maxRedirects = options.maxRedirects ?? DEFAULT_REDIRECTS_V1;\n\tif (!Number.isSafeInteger(maxRedirects) || maxRedirects < 0 || maxRedirects > MAX_REDIRECTS_V1)\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"maxRedirects must be an integer between 0 and {max}\", { max: MAX_REDIRECTS_V1 }),\n\t\t);\n\tconst userAgent = options.userAgent ?? \"agent-forge-plugin-npm/1\";\n\tif (userAgent.length === 0 || userAgent.length > 256 || /[\\r\\n]/u.test(userAgent))\n\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_configuration\", t(\"userAgent is invalid\"));\n\n\tconst fetchFollowingRedirects = async (\n\t\turl: URL,\n\t\theaders: Readonly<Record<string, string>>,\n\t\tparentSignal: AbortSignal | undefined,\n\t): Promise<{ readonly response: Response; readonly request: RequestSignal }> => {\n\t\tlet current = url;\n\t\tfor (let redirect = 0; ; redirect += 1) {\n\t\t\tconst request = requestSignal(parentSignal, timeoutMs);\n\t\t\tlet response: Response;\n\t\t\ttry {\n\t\t\t\tresponse = await transport(current.toString(), {\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\theaders: { accept: \"*/*\", \"user-agent\": userAgent, ...headers },\n\t\t\t\t\tredirect: \"manual\",\n\t\t\t\t\tsignal: request.signal,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\trequest.cleanup();\n\t\t\t\tif (request.timedOut())\n\t\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_timed_out\", t(\"npm registry request timed out\"));\n\t\t\t\tif (isAbortLike(error))\n\t\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"cancelled\", t(\"npm registry request was cancelled\"));\n\t\t\t\t// Keep the transport failure as `cause`; replacing it outright made\n\t\t\t\t// connection-level failures (DNS, TLS, ECONNREFUSED) undiagnosable.\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_failed\", t(\"npm registry request failed\"), {\n\t\t\t\t\tcause: error,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!REDIRECT_STATUS.has(response.status)) return { response, request };\n\t\t\tconst location = response.headers.get(\"location\");\n\t\t\tawait response.body?.cancel().catch(() => undefined);\n\t\t\trequest.cleanup();\n\t\t\tif (location === null || redirect >= maxRedirects)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_failed\", t(\"npm registry redirect limit exceeded\"));\n\t\t\tcurrent = tarballUrl(new URL(location, current).toString());\n\t\t}\n\t};\n\n\tconst resolveNpmPackage = async (input: {\n\t\treadonly name: string;\n\t\treadonly range?: string;\n\t\treadonly signal?: AbortSignal;\n\t}): Promise<NodeNpmPackageResolutionV1> => {\n\t\tif (input.signal?.aborted === true)\n\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"cancelled\", t(\"npm registry request was cancelled\"));\n\t\tconst endpoint = packumentUrl(registry, input.name);\n\t\tconst authorization: Readonly<Record<string, string>> =\n\t\t\ttoken === undefined ? {} : { authorization: `Bearer ${token}` };\n\t\tconst { response, request } = await fetchFollowingRedirects(endpoint, authorization, input.signal);\n\t\ttry {\n\t\t\tconst limit = rateLimitState(response);\n\t\t\tif (limit.limited) throw rateLimitError(limit);\n\t\t\tif (response.status === 404 || response.status === 403)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"package_not_found\", t(\"npm package was not found on the registry\"));\n\t\t\tif (response.status < 200 || response.status >= 300)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_failed\", t(\"npm registry request did not succeed\"));\n\t\t\tif (!isJsonResponse(response))\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm registry response must be JSON\"));\n\t\t\tconst versions = parsePackument(await readBody(response, maxResponseBytes, request));\n\t\t\tconst version = selectNpmPackageVersionV1(Object.keys(versions), input.range);\n\t\t\tconst dist = version === undefined ? undefined : versions[version]?.dist;\n\t\t\tif (\n\t\t\t\tversion === undefined ||\n\t\t\t\tdist === undefined ||\n\t\t\t\ttypeof dist.tarball !== \"string\" ||\n\t\t\t\tdist.tarball.length === 0\n\t\t\t) {\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\n\t\t\t\t\t\"version_not_found\",\n\t\t\t\t\tt(\"No npm package version matches the requested range\"),\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst integrityValue = dist.integrity;\n\t\t\tconst integrity =\n\t\t\t\ttypeof integrityValue === \"string\" && integrityValue.length > 0\n\t\t\t\t\t? sriToIntegrityV1(integrityValue)\n\t\t\t\t\t: undefined;\n\t\t\tif (integrity === undefined)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"invalid_response\", t(\"npm package version has no integrity field\"));\n\t\t\treturn {\n\t\t\t\tversion,\n\t\t\t\ttarballUrl: tarballUrl(dist.tarball).toString(),\n\t\t\t\tintegrity,\n\t\t\t\tdistInfo: dist as Readonly<Record<string, unknown>>,\n\t\t\t};\n\t\t} finally {\n\t\t\tawait response.body?.cancel().catch(() => undefined);\n\t\t\trequest.cleanup();\n\t\t}\n\t};\n\n\tconst fetchTarball = async (input: { readonly url: string; readonly signal?: AbortSignal }): Promise<Uint8Array> => {\n\t\tif (input.signal?.aborted === true)\n\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"cancelled\", t(\"npm tarball download was cancelled\"));\n\t\tconst endpoint = tarballUrl(input.url);\n\t\tconst authorization: Readonly<Record<string, string>> =\n\t\t\ttoken === undefined ? {} : { authorization: `Bearer ${token}` };\n\t\tconst { response, request } = await fetchFollowingRedirects(endpoint, authorization, input.signal);\n\t\ttry {\n\t\t\tconst limit = rateLimitState(response);\n\t\t\tif (limit.limited) throw rateLimitError(limit);\n\t\t\tif (response.status < 200 || response.status >= 300)\n\t\t\t\tthrow new NodeNpmRegistrySourceErrorV1(\"request_failed\", t(\"npm tarball download did not succeed\"));\n\t\t\treturn await readBody(response, maxTarballBytes, request);\n\t\t} finally {\n\t\t\tawait response.body?.cancel().catch(() => undefined);\n\t\t\trequest.cleanup();\n\t\t}\n\t};\n\n\treturn { version: 1, registry, resolveNpmPackage, fetchTarball };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"node-plugin-acquisition-host.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-plugin-acquisition-host.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport { lstatSync } from \"node:fs\";\nimport type { PluginDistributionArtifactV1 } from \"./distribution.ts\";\nimport { collectLocalDirectoryPackageEntriesV1, readLocalPackageFileV1 } from \"./node-local-package-source.ts\";\nimport {\n\tcreateNodeNpmRegistrySourceV1,\n\tNodeNpmRegistrySourceErrorV1,\n\ttype NodeNpmRegistrySourceV1,\n} from \"./node-npm-registry-source.ts\";\nimport {\n\tNodePackageInstallErrorV1,\n\ttype NodeZipPackageEntryV1,\n\ttype NodeZipPackageLimitsV1,\n\tparseNodeZipPackageV1,\n} from \"./node-package-install-host.ts\";\nimport { detectPluginPackageMediaTypeV1 } from \"./node-package-media.ts\";\nimport {\n\tcreateNodeReleasePackageSourceV1,\n\tNodeReleasePackageSourceErrorV1,\n\ttype NodeReleasePackageSourceV1,\n} from \"./node-release-package-source.ts\";\nimport { parseNodeTarGzPackageV1 } from \"./node-tar-package.ts\";\nimport { buildNodeTarGzBytesV1 } from \"./node-tar-writer.ts\";\nimport {\n\tPluginAcquisitionErrorV1,\n\ttype PluginAcquisitionLocalProbeV1,\n\ttype PluginAcquisitionPackageV1,\n\ttype PluginAcquisitionRefV1,\n\tparsePluginAcquisitionRefV1,\n} from \"./plugin-acquisition.ts\";\nimport type { PluginManifestV1 } from \"./types.ts\";\nimport { pluginManifestDigestV1 } from \"./updates.ts\";\n\nexport type { PluginAcquisitionPackageV1 } from \"./plugin-acquisition.ts\";\n\nimport { downloadNodeUrlPackageV1, NodeUrlPackageSourceErrorV1 } from \"./node-url-package-source.ts\";\n\n/**\n * Node acquisition orchestration for `plugin install <ref>` (design §4.6).\n * One boundary acquires package bytes for every source (npm packument+tarball,\n * GitHub/Gitee release asset, custom URL, local file, local directory),\n * verifies the source-specific integrity layer (npm SRI > ref digest fragment\n * > sha256 on exchange), discovers the `agent-forge.json` identity through the\n * shared bounded unpackers, and exposes the result as an opaque distribution\n * artifact the existing installer/install-host chain consumes unchanged.\n */\n\nconst NODE_PLUGIN_ACQUISITION_HOST_VERSION_V1 = 1 as const;\nconst MAX_PACKAGE_MANIFEST_BYTES_V1 = 64 * 1024;\nconst ECOSYSTEM_MANIFEST_FILE_V1 = \"agent-forge.json\";\n/** Fixed far-future expiry; the artifact handle is single-transaction and never persisted. */\nconst ACQUISITION_ARTIFACT_EXPIRES_AT_V1 = \"2099-01-01T00:00:00.000Z\";\nconst ARTIFACT_CHUNK_BYTES_V1 = 64 * 1024;\n\n/** Environment variable overriding the npm registry origin (bare http(s) origin). */\nexport const AGENT_FORGE_NPM_REGISTRY_ENV_V1 = \"AGENT_FORGE_NPM_REGISTRY\";\n/** Environment variable carrying the npm registry bearer token. */\nexport const AGENT_FORGE_NPM_TOKEN_ENV_V1 = \"AGENT_FORGE_NPM_TOKEN\";\n/** Environment variable overriding the GitHub release API origin (bare http(s) origin). */\nexport const AGENT_FORGE_GITHUB_API_ENV_V1 = \"AGENT_FORGE_GITHUB_API\";\n/** Environment variable overriding the Gitee release API origin (bare http(s) origin, includes the /api/v5 path). */\nexport const AGENT_FORGE_GITEE_API_ENV_V1 = \"AGENT_FORGE_GITEE_API\";\n/** Environment variable carrying the optional GitHub API token. */\nexport const GITHUB_TOKEN_ENV_V1 = \"GITHUB_TOKEN\";\n/** Environment variable carrying the optional Gitee API token. */\nexport const GITEE_TOKEN_ENV_V1 = \"GITEE_TOKEN\";\n\nexport interface NodePluginAcquisitionHostV1 {\n\treadonly version: typeof NODE_PLUGIN_ACQUISITION_HOST_VERSION_V1;\n\t/** Parse and acquire one ref into a package + artifact pair. */\n\treadonly resolvePackage: (input: {\n\t\treadonly ref: string;\n\t\treadonly signal?: AbortSignal;\n\t}) => Promise<PluginAcquisitionPackageV1>;\n\t/** Private installer-facing reader; mirrors the HTTP distribution host boundary. */\n\treadonly openArtifact: (input: {\n\t\treadonly artifact: PluginDistributionArtifactV1;\n\t\treadonly signal?: AbortSignal;\n\t}) => AsyncIterable<Uint8Array>;\n\treadonly releaseArtifact: (input: { readonly artifact: { readonly artifactRef: string } }) => Promise<void>;\n\t/** Whether this host owns the artifact reference (used to compose artifact readers). */\n\treadonly ownsArtifact: (input: { readonly artifactRef: string }) => boolean;\n\treadonly close: () => Promise<void>;\n}\n\nexport interface NodePluginAcquisitionHostOptionsV1 {\n\t/** Real fetch or a deterministic test replacement. */\n\treadonly fetch?: typeof globalThis.fetch;\n\t/** Bare http(s) npm registry origin; defaults to the environment variable, then the npm public registry. */\n\treadonly npmRegistry?: string;\n\t/** npm registry bearer token; defaults to the environment variable. */\n\treadonly npmToken?: string;\n\t/** Bare http(s) GitHub release API origin; defaults to the environment variable, then api.github.com. */\n\treadonly githubApiOrigin?: string;\n\t/** Bare http(s) Gitee release API origin; defaults to the environment variable, then gitee.com/api/v5. */\n\treadonly giteeApiOrigin?: string;\n\t/** GitHub API token sent as a bearer header; defaults to the environment variable. */\n\treadonly githubToken?: string;\n\t/** Gitee API token sent as an access_token query parameter; defaults to the environment variable. */\n\treadonly giteeToken?: string;\n\treadonly requestTimeoutMs?: number;\n\treadonly maxResponseBytes?: number;\n\treadonly maxTarballBytes?: number;\n\treadonly limits?: NodeZipPackageLimitsV1;\n\treadonly userAgent?: string;\n}\n\ninterface AcquiredBytesV1 {\n\treadonly bytes: Uint8Array;\n\treadonly mediaType: \"application/zip\" | \"application/gzip\";\n\treadonly digest: { readonly algorithm: \"sha256\" | \"sha512\"; readonly hex: string };\n\treadonly source: string;\n}\n\ninterface AcquiredArtifactRecordV1 {\n\treadonly bytes: Uint8Array;\n\treadonly artifact: PluginDistributionArtifactV1;\n}\n\nconst LOCAL_PROBE_V1: PluginAcquisitionLocalProbeV1 = {\n\t// The parser contract is synchronous; one lstat per candidate ref keeps\n\t// this bounded. Symlinks classify as \"other\" so they never install as local.\n\tstatLocalRef: (path) => {\n\t\tconst stats = lstatSync(path, { throwIfNoEntry: false });\n\t\tif (stats === undefined) return \"missing\";\n\t\tif (stats.isSymbolicLink()) return \"other\";\n\t\tif (stats.isDirectory()) return \"directory\";\n\t\tif (stats.isFile()) return \"file\";\n\t\treturn \"other\";\n\t},\n};\n\nfunction mapInstallError(error: unknown): PluginAcquisitionErrorV1 {\n\tif (error instanceof PluginAcquisitionErrorV1) return error;\n\tif (error instanceof NodePackageInstallErrorV1) {\n\t\tif (error.code === \"cancelled\") return new PluginAcquisitionErrorV1(\"cancelled\");\n\t\tif (error.code === \"archive_budget_exceeded\") return new PluginAcquisitionErrorV1(\"budget_exceeded\");\n\t\tif (error.code === \"unsupported_media_type\") return new PluginAcquisitionErrorV1(\"unsupported_media_type\");\n\t\treturn new PluginAcquisitionErrorV1(\"package_invalid\");\n\t}\n\treturn new PluginAcquisitionErrorV1(\"download_failed\");\n}\n\nfunction mapNpmError(error: unknown): PluginAcquisitionErrorV1 {\n\tif (error instanceof PluginAcquisitionErrorV1) return error;\n\tif (error instanceof NodeNpmRegistrySourceErrorV1) {\n\t\tif (error.code === \"package_not_found\") return new PluginAcquisitionErrorV1(\"package_not_found\");\n\t\tif (error.code === \"version_not_found\") return new PluginAcquisitionErrorV1(\"version_not_found\");\n\t\tif (error.code === \"cancelled\") return new PluginAcquisitionErrorV1(\"cancelled\");\n\t\tif (error.code === \"invalid_response\" || error.code === \"integrity_unsupported\")\n\t\t\treturn new PluginAcquisitionErrorV1(\"package_invalid\");\n\t\treturn new PluginAcquisitionErrorV1(\"download_failed\");\n\t}\n\treturn mapInstallError(error);\n}\n\nfunction mapUrlError(error: unknown): PluginAcquisitionErrorV1 {\n\tif (error instanceof PluginAcquisitionErrorV1) return error;\n\tif (error instanceof NodeUrlPackageSourceErrorV1) {\n\t\tif (error.code === \"digest_mismatch\") return new PluginAcquisitionErrorV1(\"digest_mismatch\");\n\t\tif (error.code === \"cancelled\") return new PluginAcquisitionErrorV1(\"cancelled\");\n\t\tif (error.code === \"invalid_url\" || error.code === \"invalid_configuration\")\n\t\t\treturn new PluginAcquisitionErrorV1(\"invalid_ref\");\n\t\tif (error.code === \"response_too_large\") return new PluginAcquisitionErrorV1(\"budget_exceeded\");\n\t\treturn new PluginAcquisitionErrorV1(\"download_failed\");\n\t}\n\treturn mapInstallError(error);\n}\n\nfunction mapReleaseError(error: unknown): PluginAcquisitionErrorV1 {\n\tif (error instanceof PluginAcquisitionErrorV1) return error;\n\tif (error instanceof NodeReleasePackageSourceErrorV1) {\n\t\tif (error.code === \"cancelled\") return new PluginAcquisitionErrorV1(\"cancelled\");\n\t\tif (error.code === \"invalid_configuration\") return new PluginAcquisitionErrorV1(\"invalid_ref\");\n\t\tif (error.code === \"response_too_large\") return new PluginAcquisitionErrorV1(\"budget_exceeded\");\n\t\tif (error.code === \"invalid_response\") return new PluginAcquisitionErrorV1(\"package_invalid\");\n\t\tif (error.code === \"rate_limited\")\n\t\t\treturn new PluginAcquisitionErrorV1(\n\t\t\t\t\"rate_limited\",\n\t\t\t\terror.resetEpochSeconds === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: `rate limit resets at ${new Date(error.resetEpochSeconds * 1000).toISOString()}`,\n\t\t\t);\n\t\tif (\n\t\t\terror.code === \"release_not_found\" ||\n\t\t\terror.code === \"release_asset_not_found\" ||\n\t\t\terror.code === \"release_asset_ambiguous\"\n\t\t)\n\t\t\treturn new PluginAcquisitionErrorV1(error.code, error.message);\n\t\treturn new PluginAcquisitionErrorV1(\"download_failed\");\n\t}\n\t// Asset downloads ride the URL package source; digest and budget errors pass through unchanged.\n\treturn mapUrlError(error);\n}\n\nfunction shaHex(algorithm: \"sha256\" | \"sha512\", bytes: Uint8Array): string {\n\treturn createHash(algorithm).update(bytes).digest(\"hex\");\n}\n\n/** Abort probe as a function so later re-checks are not flow-narrowed away after awaits. */\nfunction signalAborted(signal: AbortSignal | undefined): boolean {\n\treturn signal?.aborted === true;\n}\n\n/** Discover the `agent-forge.json` identity in already-bounded package entries. */\nexport function pluginAcquisitionManifestFromEntriesV1(entries: readonly NodeZipPackageEntryV1[]): {\n\treadonly manifest: PluginManifestV1;\n\treadonly manifestDigest: string;\n} {\n\tconst manifestEntry = entries.find((entry) => entry.name === ECOSYSTEM_MANIFEST_FILE_V1 && !entry.directory);\n\tif (manifestEntry === undefined || manifestEntry.bytes.byteLength > MAX_PACKAGE_MANIFEST_BYTES_V1)\n\t\tthrow new PluginAcquisitionErrorV1(\"package_invalid\");\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(new TextDecoder(\"utf-8\", { fatal: true }).decode(manifestEntry.bytes));\n\t} catch {\n\t\tthrow new PluginAcquisitionErrorV1(\"package_invalid\");\n\t}\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value))\n\t\tthrow new PluginAcquisitionErrorV1(\"package_invalid\");\n\tconst record = value as Record<string, unknown>;\n\tconst manifestKeys = new Set([\n\t\t\"id\",\n\t\t\"pluginVersion\",\n\t\t\"apiVersion\",\n\t\t\"minHostVersion\",\n\t\t\"maxHostVersion\",\n\t\t\"capabilityRefs\",\n\t\t\"requires\",\n\t\t\"platform\",\n\t\t\"testOnly\",\n\t]);\n\tif (\n\t\trecord.packageFormatVersion !== 1 ||\n\t\tObject.keys(record).some((key) => key !== \"packageFormatVersion\" && !manifestKeys.has(key))\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"package_invalid\");\n\tconst id = record.id;\n\tconst pluginVersion = record.pluginVersion;\n\tconst apiVersion = record.apiVersion;\n\tif (\n\t\ttypeof id !== \"string\" ||\n\t\tid.trim().length === 0 ||\n\t\tid.length > 256 ||\n\t\ttypeof pluginVersion !== \"string\" ||\n\t\tpluginVersion.trim().length === 0 ||\n\t\tpluginVersion.length > 256 ||\n\t\ttypeof apiVersion !== \"string\" ||\n\t\tapiVersion.trim().length === 0 ||\n\t\tapiVersion.length > 256\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"package_invalid\");\n\tif (record.minHostVersion === undefined && record.maxHostVersion === undefined)\n\t\tthrow new PluginAcquisitionErrorV1(\"package_invalid\");\n\tconst manifest: PluginManifestV1 = Object.freeze({\n\t\tid,\n\t\tpluginVersion,\n\t\tapiVersion,\n\t\t...(record.minHostVersion === undefined ? {} : { minHostVersion: record.minHostVersion as string }),\n\t\t...(record.maxHostVersion === undefined ? {} : { maxHostVersion: record.maxHostVersion as string }),\n\t\t...(record.capabilityRefs === undefined\n\t\t\t? {}\n\t\t\t: { capabilityRefs: record.capabilityRefs as PluginManifestV1[\"capabilityRefs\"] }),\n\t\t...(record.requires === undefined ? {} : { requires: record.requires as PluginManifestV1[\"requires\"] }),\n\t\t...(record.platform === undefined ? {} : { platform: record.platform as PluginManifestV1[\"platform\"] }),\n\t\t...(record.testOnly === undefined ? {} : { testOnly: record.testOnly as boolean }),\n\t});\n\treturn { manifest, manifestDigest: pluginManifestDigestV1(manifest) };\n}\n\n/**\n * Create the Node acquisition host. All sources share the bounded unpackers,\n * the manifest identity discovery, and the artifact reader contract used by\n * the existing install host. Nothing is downloaded until `resolvePackage`.\n */\nexport function createNodePluginAcquisitionHostV1(\n\toptions: NodePluginAcquisitionHostOptionsV1 = {},\n): NodePluginAcquisitionHostV1 {\n\tconst limits = options.limits ?? {};\n\tconst npmRegistryOption = options.npmRegistry ?? process.env[AGENT_FORGE_NPM_REGISTRY_ENV_V1]?.trim();\n\tconst npmTokenOption = options.npmToken ?? process.env[AGENT_FORGE_NPM_TOKEN_ENV_V1]?.trim();\n\tconst githubApiOriginOption = options.githubApiOrigin ?? process.env[AGENT_FORGE_GITHUB_API_ENV_V1]?.trim();\n\tconst giteeApiOriginOption = options.giteeApiOrigin ?? process.env[AGENT_FORGE_GITEE_API_ENV_V1]?.trim();\n\tconst githubTokenOption = options.githubToken ?? process.env[GITHUB_TOKEN_ENV_V1]?.trim();\n\tconst giteeTokenOption = options.giteeToken ?? process.env[GITEE_TOKEN_ENV_V1]?.trim();\n\tconst npmSource: NodeNpmRegistrySourceV1 = createNodeNpmRegistrySourceV1({\n\t\t...(npmRegistryOption === undefined || npmRegistryOption === \"\" ? {} : { registry: npmRegistryOption }),\n\t\t...(npmTokenOption === undefined || npmTokenOption === \"\" ? {} : { token: npmTokenOption }),\n\t\t...(options.fetch === undefined ? {} : { fetch: options.fetch }),\n\t\t...(options.requestTimeoutMs === undefined ? {} : { requestTimeoutMs: options.requestTimeoutMs }),\n\t\t...(options.maxResponseBytes === undefined ? {} : { maxResponseBytes: options.maxResponseBytes }),\n\t\t...(options.maxTarballBytes === undefined ? {} : { maxTarballBytes: options.maxTarballBytes }),\n\t\t...(options.userAgent === undefined ? {} : { userAgent: options.userAgent }),\n\t});\n\tconst releaseSource: NodeReleasePackageSourceV1 = createNodeReleasePackageSourceV1({\n\t\t...(githubApiOriginOption === undefined || githubApiOriginOption === \"\"\n\t\t\t? {}\n\t\t\t: { githubApiOrigin: githubApiOriginOption }),\n\t\t...(giteeApiOriginOption === undefined || giteeApiOriginOption === \"\"\n\t\t\t? {}\n\t\t\t: { giteeApiOrigin: giteeApiOriginOption }),\n\t\t...(githubTokenOption === undefined || githubTokenOption === \"\" ? {} : { githubToken: githubTokenOption }),\n\t\t...(giteeTokenOption === undefined || giteeTokenOption === \"\" ? {} : { giteeToken: giteeTokenOption }),\n\t\t...(options.fetch === undefined ? {} : { fetch: options.fetch }),\n\t\t...(options.requestTimeoutMs === undefined ? {} : { requestTimeoutMs: options.requestTimeoutMs }),\n\t\t...(options.maxResponseBytes === undefined ? {} : { maxResponseBytes: options.maxResponseBytes }),\n\t\t...(options.maxTarballBytes === undefined ? {} : { maxAssetBytes: options.maxTarballBytes }),\n\t\t...(options.userAgent === undefined ? {} : { userAgent: options.userAgent }),\n\t});\n\tconst artifacts = new Map<string, AcquiredArtifactRecordV1>();\n\tlet closed = false;\n\n\tconst acquireBytes = async (\n\t\tref: PluginAcquisitionRefV1,\n\t\tsignal: AbortSignal | undefined,\n\t): Promise<AcquiredBytesV1> => {\n\t\tif (ref.kind === \"github\" || ref.kind === \"gitee\") {\n\t\t\ttry {\n\t\t\t\tconst download = await releaseSource.downloadReleaseAsset({\n\t\t\t\t\tkind: ref.kind,\n\t\t\t\t\towner: ref.owner,\n\t\t\t\t\trepo: ref.repo,\n\t\t\t\t\t...(ref.tag === undefined ? {} : { tag: ref.tag }),\n\t\t\t\t\t...(ref.expectedDigestHex === undefined ? {} : { expectedDigestHex: ref.expectedDigestHex }),\n\t\t\t\t\tsignal,\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\tbytes: download.bytes,\n\t\t\t\t\tmediaType: download.mediaType,\n\t\t\t\t\tdigest: { algorithm: \"sha256\", hex: download.sha256Hex },\n\t\t\t\t\tsource: download.sourceLabel,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tthrow mapReleaseError(error);\n\t\t\t}\n\t\t}\n\t\tif (ref.kind === \"npm\") {\n\t\t\ttry {\n\t\t\t\tconst resolved = await npmSource.resolveNpmPackage({\n\t\t\t\t\tname: ref.name,\n\t\t\t\t\t...(ref.range === undefined ? {} : { range: ref.range }),\n\t\t\t\t\tsignal,\n\t\t\t\t});\n\t\t\t\tconst bytes = await npmSource.fetchTarball({ url: resolved.tarballUrl, signal });\n\t\t\t\tconst hex = shaHex(resolved.integrity.algorithm, bytes);\n\t\t\t\tif (hex !== resolved.integrity.hex) throw new PluginAcquisitionErrorV1(\"digest_mismatch\");\n\t\t\t\treturn {\n\t\t\t\t\tbytes,\n\t\t\t\t\tmediaType: \"application/gzip\",\n\t\t\t\t\tdigest: resolved.integrity,\n\t\t\t\t\tsource: `npm:${new URL(resolved.tarballUrl).host}`,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tthrow mapNpmError(error);\n\t\t\t}\n\t\t}\n\t\tif (ref.kind === \"url\") {\n\t\t\ttry {\n\t\t\t\tconst download = await downloadNodeUrlPackageV1(\n\t\t\t\t\t{\n\t\t\t\t\t\t...(options.fetch === undefined ? {} : { fetch: options.fetch }),\n\t\t\t\t\t\t...(options.requestTimeoutMs === undefined ? {} : { requestTimeoutMs: options.requestTimeoutMs }),\n\t\t\t\t\t\t...(options.maxTarballBytes === undefined ? {} : { maxPackageBytes: options.maxTarballBytes }),\n\t\t\t\t\t\t...(options.userAgent === undefined ? {} : { userAgent: options.userAgent }),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\turl: ref.url,\n\t\t\t\t\t\t...(ref.expectedDigestHex === undefined ? {} : { expectedDigestHex: ref.expectedDigestHex }),\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\treturn {\n\t\t\t\t\tbytes: download.bytes,\n\t\t\t\t\tmediaType: download.mediaType,\n\t\t\t\t\tdigest: { algorithm: \"sha256\", hex: download.digestHex },\n\t\t\t\t\tsource: `url:${new URL(ref.url).host}`,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tthrow mapUrlError(error);\n\t\t\t}\n\t\t}\n\t\tif (ref.kind === \"local-file\") {\n\t\t\ttry {\n\t\t\t\tconst bytes = await readLocalPackageFileV1(ref.path, limits, signal);\n\t\t\t\tconst fileName = ref.path.split(/[\\\\/]/u).pop();\n\t\t\t\tconst mediaType = detectPluginPackageMediaTypeV1(\n\t\t\t\t\tbytes,\n\t\t\t\t\tfileName === undefined || fileName.length === 0 ? undefined : fileName,\n\t\t\t\t);\n\t\t\t\treturn {\n\t\t\t\t\tbytes,\n\t\t\t\t\tmediaType,\n\t\t\t\t\tdigest: { algorithm: \"sha256\", hex: shaHex(\"sha256\", bytes) },\n\t\t\t\t\tsource: \"local:file\",\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tthrow mapInstallError(error);\n\t\t\t}\n\t\t}\n\t\tif (ref.kind === \"local-path\") {\n\t\t\ttry {\n\t\t\t\tconst entries = await collectLocalDirectoryPackageEntriesV1(ref.path, limits, signal);\n\t\t\t\tconst bytes = buildNodeTarGzBytesV1(\n\t\t\t\t\tentries.map((entry) => ({ name: entry.name, directory: entry.directory, bytes: entry.bytes })),\n\t\t\t\t);\n\t\t\t\treturn {\n\t\t\t\t\tbytes,\n\t\t\t\t\tmediaType: \"application/gzip\",\n\t\t\t\t\tdigest: { algorithm: \"sha256\", hex: shaHex(\"sha256\", bytes) },\n\t\t\t\t\tsource: \"local:dir\",\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tthrow mapInstallError(error);\n\t\t\t}\n\t\t}\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\t};\n\n\tconst releaseArtifact = async (input: { readonly artifact: { readonly artifactRef: string } }): Promise<void> => {\n\t\tif (!artifacts.delete(input.artifact.artifactRef)) throw new NodePackageInstallErrorV1(\"invalid_artifact\");\n\t};\n\n\tconst resolvePackage = async (input: {\n\t\treadonly ref: string;\n\t\treadonly signal?: AbortSignal;\n\t}): Promise<PluginAcquisitionPackageV1> => {\n\t\tif (closed || signalAborted(input.signal)) throw new PluginAcquisitionErrorV1(\"cancelled\");\n\t\tlet ref: PluginAcquisitionRefV1;\n\t\ttry {\n\t\t\tref = parsePluginAcquisitionRefV1(input.ref, LOCAL_PROBE_V1);\n\t\t} catch (error) {\n\t\t\tif (error instanceof PluginAcquisitionErrorV1) throw error;\n\t\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\t\t}\n\t\tconst acquired = await acquireBytes(ref, input.signal);\n\t\tif (signalAborted(input.signal)) throw new PluginAcquisitionErrorV1(\"cancelled\");\n\t\tlet entries: readonly NodeZipPackageEntryV1[];\n\t\ttry {\n\t\t\tentries =\n\t\t\t\tacquired.mediaType === \"application/gzip\"\n\t\t\t\t\t? await parseNodeTarGzPackageV1(acquired.bytes, limits)\n\t\t\t\t\t: parseNodeZipPackageV1(acquired.bytes, limits);\n\t\t} catch (error) {\n\t\t\tthrow mapInstallError(error);\n\t\t}\n\t\tconst identity = pluginAcquisitionManifestFromEntriesV1(entries);\n\t\tif (closed) throw new PluginAcquisitionErrorV1(\"cancelled\");\n\t\tconst artifactRef = `plugin-acquisition://node/${randomUUID()}`;\n\t\tconst artifact: PluginDistributionArtifactV1 = Object.freeze({\n\t\t\tversion: 1,\n\t\t\tsource: acquired.source,\n\t\t\tpluginId: identity.manifest.id,\n\t\t\tpluginVersion: identity.manifest.pluginVersion,\n\t\t\tmanifestDigest: identity.manifestDigest,\n\t\t\tartifactDigest:\n\t\t\t\tacquired.digest.algorithm === \"sha512\" ? `sha512:${acquired.digest.hex}` : `sha256:${acquired.digest.hex}`,\n\t\t\texpiresAt: ACQUISITION_ARTIFACT_EXPIRES_AT_V1,\n\t\t\tsizeBytes: acquired.bytes.byteLength,\n\t\t\tmediaType: acquired.mediaType,\n\t\t\tartifactRef,\n\t\t});\n\t\tartifacts.set(artifactRef, { bytes: acquired.bytes, artifact });\n\t\treturn Object.freeze({\n\t\t\tmanifest: identity.manifest,\n\t\t\tmanifestDigest: identity.manifestDigest,\n\t\t\tsource: acquired.source,\n\t\t\tartifact,\n\t\t\trelease: async () => {\n\t\t\t\ttry {\n\t\t\t\t\tawait releaseArtifact({ artifact: { artifactRef } });\n\t\t\t\t\treturn true;\n\t\t\t\t} catch {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t};\n\n\treturn {\n\t\tversion: NODE_PLUGIN_ACQUISITION_HOST_VERSION_V1,\n\t\tresolvePackage,\n\t\topenArtifact(input) {\n\t\t\treturn (async function* (): AsyncGenerator<Uint8Array> {\n\t\t\t\tconst record = artifacts.get(input.artifact.artifactRef);\n\t\t\t\tif (record === undefined) throw new NodePackageInstallErrorV1(\"invalid_artifact\");\n\t\t\t\tif (\n\t\t\t\t\trecord.artifact.pluginId !== input.artifact.pluginId ||\n\t\t\t\t\trecord.artifact.pluginVersion !== input.artifact.pluginVersion ||\n\t\t\t\t\trecord.artifact.manifestDigest !== input.artifact.manifestDigest ||\n\t\t\t\t\trecord.artifact.artifactDigest !== input.artifact.artifactDigest ||\n\t\t\t\t\trecord.artifact.sizeBytes !== input.artifact.sizeBytes\n\t\t\t\t)\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"invalid_artifact\");\n\t\t\t\tfor (let offset = 0; offset < record.bytes.byteLength; offset += ARTIFACT_CHUNK_BYTES_V1) {\n\t\t\t\t\tif (input.signal?.aborted === true) throw new NodePackageInstallErrorV1(\"cancelled\");\n\t\t\t\t\tyield new Uint8Array(\n\t\t\t\t\t\trecord.bytes.subarray(offset, Math.min(offset + ARTIFACT_CHUNK_BYTES_V1, record.bytes.byteLength)),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t})();\n\t\t},\n\t\treleaseArtifact,\n\t\townsArtifact: (input) => artifacts.has(input.artifactRef),\n\t\tasync close() {\n\t\t\tclosed = true;\n\t\t\tartifacts.clear();\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"node-plugin-acquisition-host.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-plugin-acquisition-host.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport { lstatSync } from \"node:fs\";\nimport type { PluginDistributionArtifactV1 } from \"./distribution.ts\";\nimport { collectLocalDirectoryPackageEntriesV1, readLocalPackageFileV1 } from \"./node-local-package-source.ts\";\nimport {\n\tcreateNodeNpmRegistrySourceV1,\n\tNodeNpmRegistrySourceErrorV1,\n\ttype NodeNpmRegistrySourceV1,\n} from \"./node-npm-registry-source.ts\";\nimport {\n\tNodePackageInstallErrorV1,\n\ttype NodeZipPackageEntryV1,\n\ttype NodeZipPackageLimitsV1,\n\tparseNodeZipPackageV1,\n} from \"./node-package-install-host.ts\";\nimport { detectPluginPackageMediaTypeV1 } from \"./node-package-media.ts\";\nimport {\n\tcreateNodeReleasePackageSourceV1,\n\tNodeReleasePackageSourceErrorV1,\n\ttype NodeReleasePackageSourceV1,\n} from \"./node-release-package-source.ts\";\nimport { parseNodeTarGzPackageV1 } from \"./node-tar-package.ts\";\nimport { buildNodeTarGzBytesV1 } from \"./node-tar-writer.ts\";\nimport {\n\tPluginAcquisitionErrorV1,\n\ttype PluginAcquisitionLocalProbeV1,\n\ttype PluginAcquisitionPackageV1,\n\ttype PluginAcquisitionRefV1,\n\tparsePluginAcquisitionRefV1,\n} from \"./plugin-acquisition.ts\";\nimport type { PluginManifestV1 } from \"./types.ts\";\nimport { pluginManifestDigestV1 } from \"./updates.ts\";\n\nexport type { PluginAcquisitionPackageV1 } from \"./plugin-acquisition.ts\";\n\nimport { downloadNodeUrlPackageV1, NodeUrlPackageSourceErrorV1 } from \"./node-url-package-source.ts\";\n\n/**\n * Node acquisition orchestration for `plugin install <ref>` (design §4.6).\n * One boundary acquires package bytes for every source (npm packument+tarball,\n * GitHub/Gitee release asset, custom URL, local file, local directory),\n * verifies the source-specific integrity layer (npm SRI > ref digest fragment\n * > sha256 on exchange), discovers the `agent-forge.json` identity through the\n * shared bounded unpackers, and exposes the result as an opaque distribution\n * artifact the existing installer/install-host chain consumes unchanged.\n */\n\nconst NODE_PLUGIN_ACQUISITION_HOST_VERSION_V1 = 1 as const;\nconst MAX_PACKAGE_MANIFEST_BYTES_V1 = 64 * 1024;\nconst ECOSYSTEM_MANIFEST_FILE_V1 = \"agent-forge.json\";\n/** Fixed far-future expiry; the artifact handle is single-transaction and never persisted. */\nconst ACQUISITION_ARTIFACT_EXPIRES_AT_V1 = \"2099-01-01T00:00:00.000Z\";\nconst ARTIFACT_CHUNK_BYTES_V1 = 64 * 1024;\n\n/** Environment variable overriding the npm registry origin (bare http(s) origin). */\nexport const AGENT_FORGE_NPM_REGISTRY_ENV_V1 = \"AGENT_FORGE_NPM_REGISTRY\";\n/** Environment variable carrying the npm registry bearer token. */\nexport const AGENT_FORGE_NPM_TOKEN_ENV_V1 = \"AGENT_FORGE_NPM_TOKEN\";\n/** Environment variable overriding the GitHub release API origin (bare http(s) origin). */\nexport const AGENT_FORGE_GITHUB_API_ENV_V1 = \"AGENT_FORGE_GITHUB_API\";\n/** Environment variable overriding the Gitee release API origin (bare http(s) origin, includes the /api/v5 path). */\nexport const AGENT_FORGE_GITEE_API_ENV_V1 = \"AGENT_FORGE_GITEE_API\";\n/** Environment variable carrying the optional GitHub API token. */\nexport const GITHUB_TOKEN_ENV_V1 = \"GITHUB_TOKEN\";\n/** Environment variable carrying the optional Gitee API token. */\nexport const GITEE_TOKEN_ENV_V1 = \"GITEE_TOKEN\";\n\nexport interface NodePluginAcquisitionHostV1 {\n\treadonly version: typeof NODE_PLUGIN_ACQUISITION_HOST_VERSION_V1;\n\t/** Parse and acquire one ref into a package + artifact pair. */\n\treadonly resolvePackage: (input: {\n\t\treadonly ref: string;\n\t\treadonly signal?: AbortSignal;\n\t}) => Promise<PluginAcquisitionPackageV1>;\n\t/** Private installer-facing reader; mirrors the HTTP distribution host boundary. */\n\treadonly openArtifact: (input: {\n\t\treadonly artifact: PluginDistributionArtifactV1;\n\t\treadonly signal?: AbortSignal;\n\t}) => AsyncIterable<Uint8Array>;\n\treadonly releaseArtifact: (input: { readonly artifact: { readonly artifactRef: string } }) => Promise<void>;\n\t/** Whether this host owns the artifact reference (used to compose artifact readers). */\n\treadonly ownsArtifact: (input: { readonly artifactRef: string }) => boolean;\n\treadonly close: () => Promise<void>;\n}\n\nexport interface NodePluginAcquisitionHostOptionsV1 {\n\t/** Real fetch or a deterministic test replacement. */\n\treadonly fetch?: typeof globalThis.fetch;\n\t/** Bare http(s) npm registry origin; defaults to the environment variable, then the npm public registry. */\n\treadonly npmRegistry?: string;\n\t/** npm registry bearer token; defaults to the environment variable. */\n\treadonly npmToken?: string;\n\t/** Bare http(s) GitHub release API origin; defaults to the environment variable, then api.github.com. */\n\treadonly githubApiOrigin?: string;\n\t/** Bare http(s) Gitee release API origin; defaults to the environment variable, then gitee.com/api/v5. */\n\treadonly giteeApiOrigin?: string;\n\t/** GitHub API token sent as a bearer header; defaults to the environment variable. */\n\treadonly githubToken?: string;\n\t/** Gitee API token sent as an access_token query parameter; defaults to the environment variable. */\n\treadonly giteeToken?: string;\n\treadonly requestTimeoutMs?: number;\n\treadonly maxResponseBytes?: number;\n\treadonly maxTarballBytes?: number;\n\treadonly limits?: NodeZipPackageLimitsV1;\n\treadonly userAgent?: string;\n}\n\ninterface AcquiredBytesV1 {\n\treadonly bytes: Uint8Array;\n\treadonly mediaType: \"application/zip\" | \"application/gzip\";\n\treadonly digest: { readonly algorithm: \"sha256\" | \"sha512\"; readonly hex: string };\n\treadonly source: string;\n}\n\ninterface AcquiredArtifactRecordV1 {\n\treadonly bytes: Uint8Array;\n\treadonly artifact: PluginDistributionArtifactV1;\n}\n\nconst LOCAL_PROBE_V1: PluginAcquisitionLocalProbeV1 = {\n\t// The parser contract is synchronous; one lstat per candidate ref keeps\n\t// this bounded. Symlinks classify as \"other\" so they never install as local.\n\tstatLocalRef: (path) => {\n\t\tconst stats = lstatSync(path, { throwIfNoEntry: false });\n\t\tif (stats === undefined) return \"missing\";\n\t\tif (stats.isSymbolicLink()) return \"other\";\n\t\tif (stats.isDirectory()) return \"directory\";\n\t\tif (stats.isFile()) return \"file\";\n\t\treturn \"other\";\n\t},\n};\n\nfunction mapInstallError(error: unknown): PluginAcquisitionErrorV1 {\n\tif (error instanceof PluginAcquisitionErrorV1) return error;\n\tif (error instanceof NodePackageInstallErrorV1) {\n\t\tif (error.code === \"cancelled\") return new PluginAcquisitionErrorV1(\"cancelled\");\n\t\tif (error.code === \"archive_budget_exceeded\") return new PluginAcquisitionErrorV1(\"budget_exceeded\");\n\t\tif (error.code === \"unsupported_media_type\") return new PluginAcquisitionErrorV1(\"unsupported_media_type\");\n\t\treturn new PluginAcquisitionErrorV1(\"package_invalid\");\n\t}\n\treturn new PluginAcquisitionErrorV1(\"download_failed\");\n}\n\nfunction mapNpmError(error: unknown): PluginAcquisitionErrorV1 {\n\tif (error instanceof PluginAcquisitionErrorV1) return error;\n\tif (error instanceof NodeNpmRegistrySourceErrorV1) {\n\t\tif (error.code === \"package_not_found\") return new PluginAcquisitionErrorV1(\"package_not_found\");\n\t\tif (error.code === \"version_not_found\") return new PluginAcquisitionErrorV1(\"version_not_found\");\n\t\tif (error.code === \"cancelled\") return new PluginAcquisitionErrorV1(\"cancelled\");\n\t\tif (error.code === \"rate_limited\")\n\t\t\treturn new PluginAcquisitionErrorV1(\n\t\t\t\t\"rate_limited\",\n\t\t\t\terror.retryAfterSeconds === undefined ? undefined : `retry after ${error.retryAfterSeconds}s`,\n\t\t\t);\n\t\tif (error.code === \"response_too_large\") return new PluginAcquisitionErrorV1(\"budget_exceeded\");\n\t\tif (error.code === \"request_timed_out\")\n\t\t\treturn new PluginAcquisitionErrorV1(\"download_failed\", \"request timed out\");\n\t\tif (error.code === \"invalid_response\" || error.code === \"integrity_unsupported\")\n\t\t\treturn new PluginAcquisitionErrorV1(\"package_invalid\");\n\t\treturn new PluginAcquisitionErrorV1(\"download_failed\");\n\t}\n\treturn mapInstallError(error);\n}\n\nfunction mapUrlError(error: unknown): PluginAcquisitionErrorV1 {\n\tif (error instanceof PluginAcquisitionErrorV1) return error;\n\tif (error instanceof NodeUrlPackageSourceErrorV1) {\n\t\tif (error.code === \"digest_mismatch\") return new PluginAcquisitionErrorV1(\"digest_mismatch\");\n\t\tif (error.code === \"cancelled\") return new PluginAcquisitionErrorV1(\"cancelled\");\n\t\tif (error.code === \"invalid_url\" || error.code === \"invalid_configuration\")\n\t\t\treturn new PluginAcquisitionErrorV1(\"invalid_ref\");\n\t\tif (error.code === \"response_too_large\") return new PluginAcquisitionErrorV1(\"budget_exceeded\");\n\t\treturn new PluginAcquisitionErrorV1(\"download_failed\");\n\t}\n\treturn mapInstallError(error);\n}\n\nfunction mapReleaseError(error: unknown): PluginAcquisitionErrorV1 {\n\tif (error instanceof PluginAcquisitionErrorV1) return error;\n\tif (error instanceof NodeReleasePackageSourceErrorV1) {\n\t\tif (error.code === \"cancelled\") return new PluginAcquisitionErrorV1(\"cancelled\");\n\t\tif (error.code === \"invalid_configuration\") return new PluginAcquisitionErrorV1(\"invalid_ref\");\n\t\tif (error.code === \"response_too_large\") return new PluginAcquisitionErrorV1(\"budget_exceeded\");\n\t\tif (error.code === \"invalid_response\") return new PluginAcquisitionErrorV1(\"package_invalid\");\n\t\tif (error.code === \"rate_limited\")\n\t\t\treturn new PluginAcquisitionErrorV1(\n\t\t\t\t\"rate_limited\",\n\t\t\t\terror.resetEpochSeconds === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: `rate limit resets at ${new Date(error.resetEpochSeconds * 1000).toISOString()}`,\n\t\t\t);\n\t\tif (\n\t\t\terror.code === \"release_not_found\" ||\n\t\t\terror.code === \"release_asset_not_found\" ||\n\t\t\terror.code === \"release_asset_ambiguous\"\n\t\t)\n\t\t\treturn new PluginAcquisitionErrorV1(error.code, error.message);\n\t\treturn new PluginAcquisitionErrorV1(\"download_failed\");\n\t}\n\t// Asset downloads ride the URL package source; digest and budget errors pass through unchanged.\n\treturn mapUrlError(error);\n}\n\nfunction shaHex(algorithm: \"sha256\" | \"sha512\", bytes: Uint8Array): string {\n\treturn createHash(algorithm).update(bytes).digest(\"hex\");\n}\n\n/** Abort probe as a function so later re-checks are not flow-narrowed away after awaits. */\nfunction signalAborted(signal: AbortSignal | undefined): boolean {\n\treturn signal?.aborted === true;\n}\n\n/** Discover the `agent-forge.json` identity in already-bounded package entries. */\nexport function pluginAcquisitionManifestFromEntriesV1(entries: readonly NodeZipPackageEntryV1[]): {\n\treadonly manifest: PluginManifestV1;\n\treadonly manifestDigest: string;\n} {\n\tconst manifestEntry = entries.find((entry) => entry.name === ECOSYSTEM_MANIFEST_FILE_V1 && !entry.directory);\n\tif (manifestEntry === undefined || manifestEntry.bytes.byteLength > MAX_PACKAGE_MANIFEST_BYTES_V1)\n\t\tthrow new PluginAcquisitionErrorV1(\"package_invalid\");\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(new TextDecoder(\"utf-8\", { fatal: true }).decode(manifestEntry.bytes));\n\t} catch {\n\t\tthrow new PluginAcquisitionErrorV1(\"package_invalid\");\n\t}\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value))\n\t\tthrow new PluginAcquisitionErrorV1(\"package_invalid\");\n\tconst record = value as Record<string, unknown>;\n\tconst manifestKeys = new Set([\n\t\t\"id\",\n\t\t\"pluginVersion\",\n\t\t\"apiVersion\",\n\t\t\"minHostVersion\",\n\t\t\"maxHostVersion\",\n\t\t\"capabilityRefs\",\n\t\t\"requires\",\n\t\t\"platform\",\n\t\t\"testOnly\",\n\t]);\n\tif (\n\t\trecord.packageFormatVersion !== 1 ||\n\t\tObject.keys(record).some((key) => key !== \"packageFormatVersion\" && !manifestKeys.has(key))\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"package_invalid\");\n\tconst id = record.id;\n\tconst pluginVersion = record.pluginVersion;\n\tconst apiVersion = record.apiVersion;\n\tif (\n\t\ttypeof id !== \"string\" ||\n\t\tid.trim().length === 0 ||\n\t\tid.length > 256 ||\n\t\ttypeof pluginVersion !== \"string\" ||\n\t\tpluginVersion.trim().length === 0 ||\n\t\tpluginVersion.length > 256 ||\n\t\ttypeof apiVersion !== \"string\" ||\n\t\tapiVersion.trim().length === 0 ||\n\t\tapiVersion.length > 256\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"package_invalid\");\n\tif (record.minHostVersion === undefined && record.maxHostVersion === undefined)\n\t\tthrow new PluginAcquisitionErrorV1(\"package_invalid\");\n\tconst manifest: PluginManifestV1 = Object.freeze({\n\t\tid,\n\t\tpluginVersion,\n\t\tapiVersion,\n\t\t...(record.minHostVersion === undefined ? {} : { minHostVersion: record.minHostVersion as string }),\n\t\t...(record.maxHostVersion === undefined ? {} : { maxHostVersion: record.maxHostVersion as string }),\n\t\t...(record.capabilityRefs === undefined\n\t\t\t? {}\n\t\t\t: { capabilityRefs: record.capabilityRefs as PluginManifestV1[\"capabilityRefs\"] }),\n\t\t...(record.requires === undefined ? {} : { requires: record.requires as PluginManifestV1[\"requires\"] }),\n\t\t...(record.platform === undefined ? {} : { platform: record.platform as PluginManifestV1[\"platform\"] }),\n\t\t...(record.testOnly === undefined ? {} : { testOnly: record.testOnly as boolean }),\n\t});\n\treturn { manifest, manifestDigest: pluginManifestDigestV1(manifest) };\n}\n\n/**\n * Create the Node acquisition host. All sources share the bounded unpackers,\n * the manifest identity discovery, and the artifact reader contract used by\n * the existing install host. Nothing is downloaded until `resolvePackage`.\n */\nexport function createNodePluginAcquisitionHostV1(\n\toptions: NodePluginAcquisitionHostOptionsV1 = {},\n): NodePluginAcquisitionHostV1 {\n\tconst limits = options.limits ?? {};\n\tconst npmRegistryOption = options.npmRegistry ?? process.env[AGENT_FORGE_NPM_REGISTRY_ENV_V1]?.trim();\n\tconst npmTokenOption = options.npmToken ?? process.env[AGENT_FORGE_NPM_TOKEN_ENV_V1]?.trim();\n\tconst githubApiOriginOption = options.githubApiOrigin ?? process.env[AGENT_FORGE_GITHUB_API_ENV_V1]?.trim();\n\tconst giteeApiOriginOption = options.giteeApiOrigin ?? process.env[AGENT_FORGE_GITEE_API_ENV_V1]?.trim();\n\tconst githubTokenOption = options.githubToken ?? process.env[GITHUB_TOKEN_ENV_V1]?.trim();\n\tconst giteeTokenOption = options.giteeToken ?? process.env[GITEE_TOKEN_ENV_V1]?.trim();\n\tconst npmSource: NodeNpmRegistrySourceV1 = createNodeNpmRegistrySourceV1({\n\t\t...(npmRegistryOption === undefined || npmRegistryOption === \"\" ? {} : { registry: npmRegistryOption }),\n\t\t...(npmTokenOption === undefined || npmTokenOption === \"\" ? {} : { token: npmTokenOption }),\n\t\t...(options.fetch === undefined ? {} : { fetch: options.fetch }),\n\t\t...(options.requestTimeoutMs === undefined ? {} : { requestTimeoutMs: options.requestTimeoutMs }),\n\t\t...(options.maxResponseBytes === undefined ? {} : { maxResponseBytes: options.maxResponseBytes }),\n\t\t...(options.maxTarballBytes === undefined ? {} : { maxTarballBytes: options.maxTarballBytes }),\n\t\t...(options.userAgent === undefined ? {} : { userAgent: options.userAgent }),\n\t});\n\tconst releaseSource: NodeReleasePackageSourceV1 = createNodeReleasePackageSourceV1({\n\t\t...(githubApiOriginOption === undefined || githubApiOriginOption === \"\"\n\t\t\t? {}\n\t\t\t: { githubApiOrigin: githubApiOriginOption }),\n\t\t...(giteeApiOriginOption === undefined || giteeApiOriginOption === \"\"\n\t\t\t? {}\n\t\t\t: { giteeApiOrigin: giteeApiOriginOption }),\n\t\t...(githubTokenOption === undefined || githubTokenOption === \"\" ? {} : { githubToken: githubTokenOption }),\n\t\t...(giteeTokenOption === undefined || giteeTokenOption === \"\" ? {} : { giteeToken: giteeTokenOption }),\n\t\t...(options.fetch === undefined ? {} : { fetch: options.fetch }),\n\t\t...(options.requestTimeoutMs === undefined ? {} : { requestTimeoutMs: options.requestTimeoutMs }),\n\t\t...(options.maxResponseBytes === undefined ? {} : { maxResponseBytes: options.maxResponseBytes }),\n\t\t...(options.maxTarballBytes === undefined ? {} : { maxAssetBytes: options.maxTarballBytes }),\n\t\t...(options.userAgent === undefined ? {} : { userAgent: options.userAgent }),\n\t});\n\tconst artifacts = new Map<string, AcquiredArtifactRecordV1>();\n\tlet closed = false;\n\n\tconst acquireBytes = async (\n\t\tref: PluginAcquisitionRefV1,\n\t\tsignal: AbortSignal | undefined,\n\t): Promise<AcquiredBytesV1> => {\n\t\tif (ref.kind === \"github\" || ref.kind === \"gitee\") {\n\t\t\ttry {\n\t\t\t\tconst download = await releaseSource.downloadReleaseAsset({\n\t\t\t\t\tkind: ref.kind,\n\t\t\t\t\towner: ref.owner,\n\t\t\t\t\trepo: ref.repo,\n\t\t\t\t\t...(ref.tag === undefined ? {} : { tag: ref.tag }),\n\t\t\t\t\t...(ref.expectedDigestHex === undefined ? {} : { expectedDigestHex: ref.expectedDigestHex }),\n\t\t\t\t\tsignal,\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\tbytes: download.bytes,\n\t\t\t\t\tmediaType: download.mediaType,\n\t\t\t\t\tdigest: { algorithm: \"sha256\", hex: download.sha256Hex },\n\t\t\t\t\tsource: download.sourceLabel,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tthrow mapReleaseError(error);\n\t\t\t}\n\t\t}\n\t\tif (ref.kind === \"npm\") {\n\t\t\ttry {\n\t\t\t\tconst resolved = await npmSource.resolveNpmPackage({\n\t\t\t\t\tname: ref.name,\n\t\t\t\t\t...(ref.range === undefined ? {} : { range: ref.range }),\n\t\t\t\t\tsignal,\n\t\t\t\t});\n\t\t\t\tconst bytes = await npmSource.fetchTarball({ url: resolved.tarballUrl, signal });\n\t\t\t\tconst hex = shaHex(resolved.integrity.algorithm, bytes);\n\t\t\t\tif (hex !== resolved.integrity.hex) throw new PluginAcquisitionErrorV1(\"digest_mismatch\");\n\t\t\t\treturn {\n\t\t\t\t\tbytes,\n\t\t\t\t\tmediaType: \"application/gzip\",\n\t\t\t\t\tdigest: resolved.integrity,\n\t\t\t\t\tsource: `npm:${new URL(resolved.tarballUrl).host}`,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tthrow mapNpmError(error);\n\t\t\t}\n\t\t}\n\t\tif (ref.kind === \"url\") {\n\t\t\ttry {\n\t\t\t\tconst download = await downloadNodeUrlPackageV1(\n\t\t\t\t\t{\n\t\t\t\t\t\t...(options.fetch === undefined ? {} : { fetch: options.fetch }),\n\t\t\t\t\t\t...(options.requestTimeoutMs === undefined ? {} : { requestTimeoutMs: options.requestTimeoutMs }),\n\t\t\t\t\t\t...(options.maxTarballBytes === undefined ? {} : { maxPackageBytes: options.maxTarballBytes }),\n\t\t\t\t\t\t...(options.userAgent === undefined ? {} : { userAgent: options.userAgent }),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\turl: ref.url,\n\t\t\t\t\t\t...(ref.expectedDigestHex === undefined ? {} : { expectedDigestHex: ref.expectedDigestHex }),\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\treturn {\n\t\t\t\t\tbytes: download.bytes,\n\t\t\t\t\tmediaType: download.mediaType,\n\t\t\t\t\tdigest: { algorithm: \"sha256\", hex: download.digestHex },\n\t\t\t\t\tsource: `url:${new URL(ref.url).host}`,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tthrow mapUrlError(error);\n\t\t\t}\n\t\t}\n\t\tif (ref.kind === \"local-file\") {\n\t\t\ttry {\n\t\t\t\tconst bytes = await readLocalPackageFileV1(ref.path, limits, signal);\n\t\t\t\tconst fileName = ref.path.split(/[\\\\/]/u).pop();\n\t\t\t\tconst mediaType = detectPluginPackageMediaTypeV1(\n\t\t\t\t\tbytes,\n\t\t\t\t\tfileName === undefined || fileName.length === 0 ? undefined : fileName,\n\t\t\t\t);\n\t\t\t\treturn {\n\t\t\t\t\tbytes,\n\t\t\t\t\tmediaType,\n\t\t\t\t\tdigest: { algorithm: \"sha256\", hex: shaHex(\"sha256\", bytes) },\n\t\t\t\t\tsource: \"local:file\",\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tthrow mapInstallError(error);\n\t\t\t}\n\t\t}\n\t\tif (ref.kind === \"local-path\") {\n\t\t\ttry {\n\t\t\t\tconst entries = await collectLocalDirectoryPackageEntriesV1(ref.path, limits, signal);\n\t\t\t\tconst bytes = buildNodeTarGzBytesV1(\n\t\t\t\t\tentries.map((entry) => ({ name: entry.name, directory: entry.directory, bytes: entry.bytes })),\n\t\t\t\t);\n\t\t\t\treturn {\n\t\t\t\t\tbytes,\n\t\t\t\t\tmediaType: \"application/gzip\",\n\t\t\t\t\tdigest: { algorithm: \"sha256\", hex: shaHex(\"sha256\", bytes) },\n\t\t\t\t\tsource: \"local:dir\",\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tthrow mapInstallError(error);\n\t\t\t}\n\t\t}\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\t};\n\n\tconst releaseArtifact = async (input: { readonly artifact: { readonly artifactRef: string } }): Promise<void> => {\n\t\tif (!artifacts.delete(input.artifact.artifactRef)) throw new NodePackageInstallErrorV1(\"invalid_artifact\");\n\t};\n\n\tconst resolvePackage = async (input: {\n\t\treadonly ref: string;\n\t\treadonly signal?: AbortSignal;\n\t}): Promise<PluginAcquisitionPackageV1> => {\n\t\tif (closed || signalAborted(input.signal)) throw new PluginAcquisitionErrorV1(\"cancelled\");\n\t\tlet ref: PluginAcquisitionRefV1;\n\t\ttry {\n\t\t\tref = parsePluginAcquisitionRefV1(input.ref, LOCAL_PROBE_V1);\n\t\t} catch (error) {\n\t\t\tif (error instanceof PluginAcquisitionErrorV1) throw error;\n\t\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\t\t}\n\t\tconst acquired = await acquireBytes(ref, input.signal);\n\t\tif (signalAborted(input.signal)) throw new PluginAcquisitionErrorV1(\"cancelled\");\n\t\tlet entries: readonly NodeZipPackageEntryV1[];\n\t\ttry {\n\t\t\tentries =\n\t\t\t\tacquired.mediaType === \"application/gzip\"\n\t\t\t\t\t? await parseNodeTarGzPackageV1(acquired.bytes, limits)\n\t\t\t\t\t: parseNodeZipPackageV1(acquired.bytes, limits);\n\t\t} catch (error) {\n\t\t\tthrow mapInstallError(error);\n\t\t}\n\t\tconst identity = pluginAcquisitionManifestFromEntriesV1(entries);\n\t\tif (closed) throw new PluginAcquisitionErrorV1(\"cancelled\");\n\t\tconst artifactRef = `plugin-acquisition://node/${randomUUID()}`;\n\t\tconst artifact: PluginDistributionArtifactV1 = Object.freeze({\n\t\t\tversion: 1,\n\t\t\tsource: acquired.source,\n\t\t\tpluginId: identity.manifest.id,\n\t\t\tpluginVersion: identity.manifest.pluginVersion,\n\t\t\tmanifestDigest: identity.manifestDigest,\n\t\t\tartifactDigest:\n\t\t\t\tacquired.digest.algorithm === \"sha512\" ? `sha512:${acquired.digest.hex}` : `sha256:${acquired.digest.hex}`,\n\t\t\texpiresAt: ACQUISITION_ARTIFACT_EXPIRES_AT_V1,\n\t\t\tsizeBytes: acquired.bytes.byteLength,\n\t\t\tmediaType: acquired.mediaType,\n\t\t\tartifactRef,\n\t\t});\n\t\tartifacts.set(artifactRef, { bytes: acquired.bytes, artifact });\n\t\treturn Object.freeze({\n\t\t\tmanifest: identity.manifest,\n\t\t\tmanifestDigest: identity.manifestDigest,\n\t\t\tsource: acquired.source,\n\t\t\tartifact,\n\t\t\trelease: async () => {\n\t\t\t\ttry {\n\t\t\t\t\tawait releaseArtifact({ artifact: { artifactRef } });\n\t\t\t\t\treturn true;\n\t\t\t\t} catch {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t};\n\n\treturn {\n\t\tversion: NODE_PLUGIN_ACQUISITION_HOST_VERSION_V1,\n\t\tresolvePackage,\n\t\topenArtifact(input) {\n\t\t\treturn (async function* (): AsyncGenerator<Uint8Array> {\n\t\t\t\tconst record = artifacts.get(input.artifact.artifactRef);\n\t\t\t\tif (record === undefined) throw new NodePackageInstallErrorV1(\"invalid_artifact\");\n\t\t\t\tif (\n\t\t\t\t\trecord.artifact.pluginId !== input.artifact.pluginId ||\n\t\t\t\t\trecord.artifact.pluginVersion !== input.artifact.pluginVersion ||\n\t\t\t\t\trecord.artifact.manifestDigest !== input.artifact.manifestDigest ||\n\t\t\t\t\trecord.artifact.artifactDigest !== input.artifact.artifactDigest ||\n\t\t\t\t\trecord.artifact.sizeBytes !== input.artifact.sizeBytes\n\t\t\t\t)\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"invalid_artifact\");\n\t\t\t\tfor (let offset = 0; offset < record.bytes.byteLength; offset += ARTIFACT_CHUNK_BYTES_V1) {\n\t\t\t\t\tif (input.signal?.aborted === true) throw new NodePackageInstallErrorV1(\"cancelled\");\n\t\t\t\t\tyield new Uint8Array(\n\t\t\t\t\t\trecord.bytes.subarray(offset, Math.min(offset + ARTIFACT_CHUNK_BYTES_V1, record.bytes.byteLength)),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t})();\n\t\t},\n\t\treleaseArtifact,\n\t\townsArtifact: (input) => artifacts.has(input.artifactRef),\n\t\tasync close() {\n\t\t\tclosed = true;\n\t\t\tartifacts.clear();\n\t\t},\n\t};\n}\n"]}
@@ -77,6 +77,12 @@ function mapNpmError(error) {
77
77
  return new PluginAcquisitionErrorV1("version_not_found");
78
78
  if (error.code === "cancelled")
79
79
  return new PluginAcquisitionErrorV1("cancelled");
80
+ if (error.code === "rate_limited")
81
+ return new PluginAcquisitionErrorV1("rate_limited", error.retryAfterSeconds === undefined ? undefined : `retry after ${error.retryAfterSeconds}s`);
82
+ if (error.code === "response_too_large")
83
+ return new PluginAcquisitionErrorV1("budget_exceeded");
84
+ if (error.code === "request_timed_out")
85
+ return new PluginAcquisitionErrorV1("download_failed", "request timed out");
80
86
  if (error.code === "invalid_response" || error.code === "integrity_unsupported")
81
87
  return new PluginAcquisitionErrorV1("package_invalid");
82
88
  return new PluginAcquisitionErrorV1("download_failed");