@fgv/ts-extras 5.1.0-5 → 5.1.0-50

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 (488) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +90 -0
  3. package/dist/index.browser.js +6 -2
  4. package/dist/index.browser.js.map +1 -0
  5. package/dist/index.js +2 -1
  6. package/dist/index.js.map +1 -0
  7. package/dist/packlets/ai-assist/chatRequestBuilders.js +282 -0
  8. package/dist/packlets/ai-assist/chatRequestBuilders.js.map +1 -0
  9. package/dist/packlets/ai-assist/{apiClient.js → completionClient.js} +165 -214
  10. package/dist/packlets/ai-assist/completionClient.js.map +1 -0
  11. package/dist/packlets/ai-assist/converters.js +47 -3
  12. package/dist/packlets/ai-assist/converters.js.map +1 -0
  13. package/dist/packlets/ai-assist/embeddingClient.js +345 -0
  14. package/dist/packlets/ai-assist/embeddingClient.js.map +1 -0
  15. package/dist/packlets/ai-assist/endpoint.js +107 -0
  16. package/dist/packlets/ai-assist/endpoint.js.map +1 -0
  17. package/dist/packlets/ai-assist/http.js +104 -0
  18. package/dist/packlets/ai-assist/http.js.map +1 -0
  19. package/dist/packlets/ai-assist/imageGenerationClient.js +454 -0
  20. package/dist/packlets/ai-assist/imageGenerationClient.js.map +1 -0
  21. package/dist/packlets/ai-assist/imageOptionsResolver.js +193 -0
  22. package/dist/packlets/ai-assist/imageOptionsResolver.js.map +1 -0
  23. package/dist/packlets/ai-assist/index.js +12 -4
  24. package/dist/packlets/ai-assist/index.js.map +1 -0
  25. package/dist/packlets/ai-assist/jsonCompletion.js +93 -0
  26. package/dist/packlets/ai-assist/jsonCompletion.js.map +1 -0
  27. package/dist/packlets/ai-assist/jsonResponse.js +423 -0
  28. package/dist/packlets/ai-assist/jsonResponse.js.map +1 -0
  29. package/dist/packlets/ai-assist/listModelsClient.js +294 -0
  30. package/dist/packlets/ai-assist/listModelsClient.js.map +1 -0
  31. package/dist/packlets/ai-assist/model.js +301 -9
  32. package/dist/packlets/ai-assist/model.js.map +1 -0
  33. package/dist/packlets/ai-assist/registry.js +376 -12
  34. package/dist/packlets/ai-assist/registry.js.map +1 -0
  35. package/dist/packlets/ai-assist/sseParser.js +123 -0
  36. package/dist/packlets/ai-assist/sseParser.js.map +1 -0
  37. package/dist/packlets/ai-assist/streamingAdapters/anthropic.js +376 -0
  38. package/dist/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -0
  39. package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +687 -0
  40. package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -0
  41. package/dist/packlets/ai-assist/streamingAdapters/common.js +187 -0
  42. package/dist/packlets/ai-assist/streamingAdapters/common.js.map +1 -0
  43. package/dist/packlets/ai-assist/streamingAdapters/gemini.js +208 -0
  44. package/dist/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -0
  45. package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js +175 -0
  46. package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -0
  47. package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js +390 -0
  48. package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -0
  49. package/dist/packlets/ai-assist/streamingAdapters/proxy.js +178 -0
  50. package/dist/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -0
  51. package/dist/packlets/ai-assist/streamingClient.js +140 -0
  52. package/dist/packlets/ai-assist/streamingClient.js.map +1 -0
  53. package/dist/packlets/ai-assist/thinkingOptionsResolver.js +288 -0
  54. package/dist/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -0
  55. package/dist/packlets/ai-assist/toolFormats.js +106 -10
  56. package/dist/packlets/ai-assist/toolFormats.js.map +1 -0
  57. package/dist/packlets/conversion/converters.js +35 -1
  58. package/dist/packlets/conversion/converters.js.map +1 -0
  59. package/dist/packlets/conversion/index.js.map +1 -0
  60. package/dist/packlets/crypto-utils/constants.js.map +1 -0
  61. package/dist/packlets/crypto-utils/converters.js +42 -4
  62. package/dist/packlets/crypto-utils/converters.js.map +1 -0
  63. package/dist/packlets/crypto-utils/directEncryptionProvider.js.map +1 -0
  64. package/dist/packlets/crypto-utils/encryptedFile.js +37 -0
  65. package/dist/packlets/crypto-utils/encryptedFile.js.map +1 -0
  66. package/dist/packlets/crypto-utils/hpkeProvider.js +355 -0
  67. package/dist/packlets/crypto-utils/hpkeProvider.js.map +1 -0
  68. package/dist/packlets/crypto-utils/index.browser.js +13 -2
  69. package/dist/packlets/crypto-utils/index.browser.js.map +1 -0
  70. package/dist/packlets/crypto-utils/index.js +9 -1
  71. package/dist/packlets/crypto-utils/index.js.map +1 -0
  72. package/dist/packlets/crypto-utils/keyPairAlgorithmParams.js +71 -0
  73. package/dist/packlets/crypto-utils/keyPairAlgorithmParams.js.map +1 -0
  74. package/dist/packlets/crypto-utils/keystore/converters.js +111 -16
  75. package/dist/packlets/crypto-utils/keystore/converters.js.map +1 -0
  76. package/dist/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js +287 -0
  77. package/dist/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js.map +1 -0
  78. package/dist/packlets/crypto-utils/keystore/index.browser.js +36 -0
  79. package/dist/packlets/crypto-utils/keystore/index.browser.js.map +1 -0
  80. package/dist/packlets/crypto-utils/keystore/index.js +3 -0
  81. package/dist/packlets/crypto-utils/keystore/index.js.map +1 -0
  82. package/dist/packlets/crypto-utils/keystore/keyStore.js +872 -119
  83. package/dist/packlets/crypto-utils/keystore/keyStore.js.map +1 -0
  84. package/dist/packlets/crypto-utils/keystore/model.js +35 -4
  85. package/dist/packlets/crypto-utils/keystore/model.js.map +1 -0
  86. package/dist/packlets/crypto-utils/keystore/privateKeyStorage.js +21 -0
  87. package/dist/packlets/crypto-utils/keystore/privateKeyStorage.js.map +1 -0
  88. package/dist/packlets/crypto-utils/model.js +32 -0
  89. package/dist/packlets/crypto-utils/model.js.map +1 -0
  90. package/dist/packlets/crypto-utils/nodeCryptoProvider.js +347 -1
  91. package/dist/packlets/crypto-utils/nodeCryptoProvider.js.map +1 -0
  92. package/dist/packlets/crypto-utils/seedDerivedKeyPair.js +120 -0
  93. package/dist/packlets/crypto-utils/seedDerivedKeyPair.js.map +1 -0
  94. package/dist/packlets/crypto-utils/spkiHelpers.js +284 -0
  95. package/dist/packlets/crypto-utils/spkiHelpers.js.map +1 -0
  96. package/dist/packlets/csv/csvFileHelpers.js +0 -14
  97. package/dist/packlets/csv/csvFileHelpers.js.map +1 -0
  98. package/dist/packlets/csv/csvHelpers.js +14 -0
  99. package/dist/packlets/csv/csvHelpers.js.map +1 -0
  100. package/dist/packlets/csv/index.browser.js +1 -3
  101. package/dist/packlets/csv/index.browser.js.map +1 -0
  102. package/dist/packlets/csv/index.js.map +1 -0
  103. package/dist/packlets/experimental/extendedArray.js.map +1 -0
  104. package/dist/packlets/experimental/formatter.js.map +1 -0
  105. package/dist/packlets/experimental/index.js.map +1 -0
  106. package/dist/packlets/experimental/rangeOf.js.map +1 -0
  107. package/dist/packlets/hash/index.browser.js.map +1 -0
  108. package/dist/packlets/hash/index.js.map +1 -0
  109. package/dist/packlets/hash/index.node.js.map +1 -0
  110. package/dist/packlets/hash/md5Normalizer.browser.js.map +1 -0
  111. package/dist/packlets/hash/md5Normalizer.js.map +1 -0
  112. package/dist/packlets/mustache/index.js.map +1 -0
  113. package/dist/packlets/mustache/interfaces.js.map +1 -0
  114. package/dist/packlets/mustache/mustacheTemplate.js +42 -4
  115. package/dist/packlets/mustache/mustacheTemplate.js.map +1 -0
  116. package/dist/packlets/record-jar/index.browser.js +1 -3
  117. package/dist/packlets/record-jar/index.browser.js.map +1 -0
  118. package/dist/packlets/record-jar/index.js.map +1 -0
  119. package/dist/packlets/record-jar/recordJarFileHelpers.js +0 -18
  120. package/dist/packlets/record-jar/recordJarFileHelpers.js.map +1 -0
  121. package/dist/packlets/record-jar/recordJarHelpers.js +18 -0
  122. package/dist/packlets/record-jar/recordJarHelpers.js.map +1 -0
  123. package/dist/packlets/safer-fetch/addressClassification.js +438 -0
  124. package/dist/packlets/safer-fetch/addressClassification.js.map +1 -0
  125. package/dist/packlets/safer-fetch/addressPolicy.js +119 -0
  126. package/dist/packlets/safer-fetch/addressPolicy.js.map +1 -0
  127. package/dist/packlets/safer-fetch/contentType.js +120 -0
  128. package/dist/packlets/safer-fetch/contentType.js.map +1 -0
  129. package/dist/packlets/safer-fetch/deadline.js +254 -0
  130. package/dist/packlets/safer-fetch/deadline.js.map +1 -0
  131. package/dist/packlets/safer-fetch/defaults.js +131 -0
  132. package/dist/packlets/safer-fetch/defaults.js.map +1 -0
  133. package/dist/packlets/safer-fetch/failureReason.js +21 -0
  134. package/dist/packlets/safer-fetch/failureReason.js.map +1 -0
  135. package/dist/packlets/safer-fetch/guards.js +148 -0
  136. package/dist/packlets/safer-fetch/guards.js.map +1 -0
  137. package/dist/packlets/safer-fetch/index.browser.js +58 -0
  138. package/dist/packlets/safer-fetch/index.browser.js.map +1 -0
  139. package/dist/packlets/safer-fetch/index.js +52 -0
  140. package/dist/packlets/safer-fetch/index.js.map +1 -0
  141. package/dist/packlets/safer-fetch/model.js +21 -0
  142. package/dist/packlets/safer-fetch/model.js.map +1 -0
  143. package/dist/packlets/safer-fetch/nodeAddressGuard.js +191 -0
  144. package/dist/packlets/safer-fetch/nodeAddressGuard.js.map +1 -0
  145. package/dist/packlets/safer-fetch/redirect.js +93 -0
  146. package/dist/packlets/safer-fetch/redirect.js.map +1 -0
  147. package/dist/packlets/safer-fetch/retry.js +188 -0
  148. package/dist/packlets/safer-fetch/retry.js.map +1 -0
  149. package/dist/packlets/safer-fetch/saferFetch.js +755 -0
  150. package/dist/packlets/safer-fetch/saferFetch.js.map +1 -0
  151. package/dist/packlets/safer-fetch/transport.js +50 -0
  152. package/dist/packlets/safer-fetch/transport.js.map +1 -0
  153. package/dist/packlets/yaml/converters.js.map +1 -0
  154. package/dist/packlets/yaml/index.js +1 -0
  155. package/dist/packlets/yaml/index.js.map +1 -0
  156. package/dist/packlets/yaml/serializers.js +48 -0
  157. package/dist/packlets/yaml/serializers.js.map +1 -0
  158. package/dist/packlets/zip-file-tree/index.js.map +1 -0
  159. package/dist/packlets/zip-file-tree/zipFileTreeAccessors.js +99 -9
  160. package/dist/packlets/zip-file-tree/zipFileTreeAccessors.js.map +1 -0
  161. package/dist/packlets/zip-file-tree/zipFileTreeWriter.js +16 -1
  162. package/dist/packlets/zip-file-tree/zipFileTreeWriter.js.map +1 -0
  163. package/dist/ts-extras.d.ts +6648 -553
  164. package/dist/tsdoc-metadata.json +1 -1
  165. package/lib/index.browser.d.ts +5 -2
  166. package/lib/index.browser.d.ts.map +1 -0
  167. package/lib/index.browser.js +11 -3
  168. package/lib/index.browser.js.map +1 -0
  169. package/lib/index.d.ts +2 -1
  170. package/lib/index.d.ts.map +1 -0
  171. package/lib/index.js +3 -1
  172. package/lib/index.js.map +1 -0
  173. package/lib/packlets/ai-assist/chatRequestBuilders.d.ts +149 -0
  174. package/lib/packlets/ai-assist/chatRequestBuilders.d.ts.map +1 -0
  175. package/lib/packlets/ai-assist/chatRequestBuilders.js +293 -0
  176. package/lib/packlets/ai-assist/chatRequestBuilders.js.map +1 -0
  177. package/lib/packlets/ai-assist/completionClient.d.ts +74 -0
  178. package/lib/packlets/ai-assist/completionClient.d.ts.map +1 -0
  179. package/lib/packlets/ai-assist/{apiClient.js → completionClient.js} +164 -213
  180. package/lib/packlets/ai-assist/completionClient.js.map +1 -0
  181. package/lib/packlets/ai-assist/converters.d.ts +15 -1
  182. package/lib/packlets/ai-assist/converters.d.ts.map +1 -0
  183. package/lib/packlets/ai-assist/converters.js +47 -3
  184. package/lib/packlets/ai-assist/converters.js.map +1 -0
  185. package/lib/packlets/ai-assist/embeddingClient.d.ts +69 -0
  186. package/lib/packlets/ai-assist/embeddingClient.d.ts.map +1 -0
  187. package/lib/packlets/ai-assist/embeddingClient.js +349 -0
  188. package/lib/packlets/ai-assist/embeddingClient.js.map +1 -0
  189. package/lib/packlets/ai-assist/endpoint.d.ts +49 -0
  190. package/lib/packlets/ai-assist/endpoint.d.ts.map +1 -0
  191. package/lib/packlets/ai-assist/endpoint.js +113 -0
  192. package/lib/packlets/ai-assist/endpoint.js.map +1 -0
  193. package/lib/packlets/ai-assist/http.d.ts +34 -0
  194. package/lib/packlets/ai-assist/http.d.ts.map +1 -0
  195. package/lib/packlets/ai-assist/http.js +109 -0
  196. package/lib/packlets/ai-assist/http.js.map +1 -0
  197. package/lib/packlets/ai-assist/imageGenerationClient.d.ts +46 -0
  198. package/lib/packlets/ai-assist/imageGenerationClient.d.ts.map +1 -0
  199. package/lib/packlets/ai-assist/imageGenerationClient.js +458 -0
  200. package/lib/packlets/ai-assist/imageGenerationClient.js.map +1 -0
  201. package/lib/packlets/ai-assist/imageOptionsResolver.d.ts +66 -0
  202. package/lib/packlets/ai-assist/imageOptionsResolver.d.ts.map +1 -0
  203. package/lib/packlets/ai-assist/imageOptionsResolver.js +197 -0
  204. package/lib/packlets/ai-assist/imageOptionsResolver.js.map +1 -0
  205. package/lib/packlets/ai-assist/index.d.ts +12 -4
  206. package/lib/packlets/ai-assist/index.d.ts.map +1 -0
  207. package/lib/packlets/ai-assist/index.js +47 -4
  208. package/lib/packlets/ai-assist/index.js.map +1 -0
  209. package/lib/packlets/ai-assist/jsonCompletion.d.ts +93 -0
  210. package/lib/packlets/ai-assist/jsonCompletion.d.ts.map +1 -0
  211. package/lib/packlets/ai-assist/jsonCompletion.js +97 -0
  212. package/lib/packlets/ai-assist/jsonCompletion.js.map +1 -0
  213. package/lib/packlets/ai-assist/jsonResponse.d.ts +194 -0
  214. package/lib/packlets/ai-assist/jsonResponse.d.ts.map +1 -0
  215. package/lib/packlets/ai-assist/jsonResponse.js +429 -0
  216. package/lib/packlets/ai-assist/jsonResponse.js.map +1 -0
  217. package/lib/packlets/ai-assist/listModelsClient.d.ts +46 -0
  218. package/lib/packlets/ai-assist/listModelsClient.d.ts.map +1 -0
  219. package/lib/packlets/ai-assist/listModelsClient.js +298 -0
  220. package/lib/packlets/ai-assist/listModelsClient.js.map +1 -0
  221. package/lib/packlets/ai-assist/model.d.ts +1346 -12
  222. package/lib/packlets/ai-assist/model.d.ts.map +1 -0
  223. package/lib/packlets/ai-assist/model.js +309 -10
  224. package/lib/packlets/ai-assist/model.js.map +1 -0
  225. package/lib/packlets/ai-assist/registry.d.ts +76 -1
  226. package/lib/packlets/ai-assist/registry.d.ts.map +1 -0
  227. package/lib/packlets/ai-assist/registry.js +381 -13
  228. package/lib/packlets/ai-assist/registry.js.map +1 -0
  229. package/lib/packlets/ai-assist/sseParser.d.ts +45 -0
  230. package/lib/packlets/ai-assist/sseParser.d.ts.map +1 -0
  231. package/lib/packlets/ai-assist/sseParser.js +128 -0
  232. package/lib/packlets/ai-assist/sseParser.js.map +1 -0
  233. package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts +72 -0
  234. package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts.map +1 -0
  235. package/lib/packlets/ai-assist/streamingAdapters/anthropic.js +379 -0
  236. package/lib/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -0
  237. package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts +269 -0
  238. package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts.map +1 -0
  239. package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +694 -0
  240. package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -0
  241. package/lib/packlets/ai-assist/streamingAdapters/common.d.ts +163 -0
  242. package/lib/packlets/ai-assist/streamingAdapters/common.d.ts.map +1 -0
  243. package/lib/packlets/ai-assist/streamingAdapters/common.js +193 -0
  244. package/lib/packlets/ai-assist/streamingAdapters/common.js.map +1 -0
  245. package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts +43 -0
  246. package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts.map +1 -0
  247. package/lib/packlets/ai-assist/streamingAdapters/gemini.js +211 -0
  248. package/lib/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -0
  249. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts +19 -0
  250. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts.map +1 -0
  251. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js +178 -0
  252. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -0
  253. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts +33 -0
  254. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts.map +1 -0
  255. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js +393 -0
  256. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -0
  257. package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts +34 -0
  258. package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts.map +1 -0
  259. package/lib/packlets/ai-assist/streamingAdapters/proxy.js +181 -0
  260. package/lib/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -0
  261. package/lib/packlets/ai-assist/streamingClient.d.ts +50 -0
  262. package/lib/packlets/ai-assist/streamingClient.d.ts.map +1 -0
  263. package/lib/packlets/ai-assist/streamingClient.js +146 -0
  264. package/lib/packlets/ai-assist/streamingClient.js.map +1 -0
  265. package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts +87 -0
  266. package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts.map +1 -0
  267. package/lib/packlets/ai-assist/thinkingOptionsResolver.js +294 -0
  268. package/lib/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -0
  269. package/lib/packlets/ai-assist/toolFormats.d.ts +40 -9
  270. package/lib/packlets/ai-assist/toolFormats.d.ts.map +1 -0
  271. package/lib/packlets/ai-assist/toolFormats.js +107 -10
  272. package/lib/packlets/ai-assist/toolFormats.js.map +1 -0
  273. package/lib/packlets/conversion/converters.d.ts +8 -1
  274. package/lib/packlets/conversion/converters.d.ts.map +1 -0
  275. package/lib/packlets/conversion/converters.js +36 -2
  276. package/lib/packlets/conversion/converters.js.map +1 -0
  277. package/lib/packlets/conversion/index.d.ts.map +1 -0
  278. package/lib/packlets/conversion/index.js.map +1 -0
  279. package/lib/packlets/crypto-utils/constants.d.ts.map +1 -0
  280. package/lib/packlets/crypto-utils/constants.js.map +1 -0
  281. package/lib/packlets/crypto-utils/converters.d.ts +20 -1
  282. package/lib/packlets/crypto-utils/converters.d.ts.map +1 -0
  283. package/lib/packlets/crypto-utils/converters.js +43 -5
  284. package/lib/packlets/crypto-utils/converters.js.map +1 -0
  285. package/lib/packlets/crypto-utils/directEncryptionProvider.d.ts.map +1 -0
  286. package/lib/packlets/crypto-utils/directEncryptionProvider.js.map +1 -0
  287. package/lib/packlets/crypto-utils/encryptedFile.d.ts +25 -0
  288. package/lib/packlets/crypto-utils/encryptedFile.d.ts.map +1 -0
  289. package/lib/packlets/crypto-utils/encryptedFile.js +38 -0
  290. package/lib/packlets/crypto-utils/encryptedFile.js.map +1 -0
  291. package/lib/packlets/crypto-utils/hpkeProvider.d.ts +150 -0
  292. package/lib/packlets/crypto-utils/hpkeProvider.d.ts.map +1 -0
  293. package/lib/packlets/crypto-utils/hpkeProvider.js +359 -0
  294. package/lib/packlets/crypto-utils/hpkeProvider.js.map +1 -0
  295. package/lib/packlets/crypto-utils/index.browser.d.ts +5 -1
  296. package/lib/packlets/crypto-utils/index.browser.d.ts.map +1 -0
  297. package/lib/packlets/crypto-utils/index.browser.js +28 -3
  298. package/lib/packlets/crypto-utils/index.browser.js.map +1 -0
  299. package/lib/packlets/crypto-utils/index.d.ts +5 -1
  300. package/lib/packlets/crypto-utils/index.d.ts.map +1 -0
  301. package/lib/packlets/crypto-utils/index.js +24 -1
  302. package/lib/packlets/crypto-utils/index.js.map +1 -0
  303. package/lib/packlets/crypto-utils/keyPairAlgorithmParams.d.ts +54 -0
  304. package/lib/packlets/crypto-utils/keyPairAlgorithmParams.d.ts.map +1 -0
  305. package/lib/packlets/crypto-utils/keyPairAlgorithmParams.js +74 -0
  306. package/lib/packlets/crypto-utils/keyPairAlgorithmParams.js.map +1 -0
  307. package/lib/packlets/crypto-utils/keystore/converters.d.ts +68 -6
  308. package/lib/packlets/crypto-utils/keystore/converters.d.ts.map +1 -0
  309. package/lib/packlets/crypto-utils/keystore/converters.js +109 -14
  310. package/lib/packlets/crypto-utils/keystore/converters.js.map +1 -0
  311. package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.d.ts +148 -0
  312. package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.d.ts.map +1 -0
  313. package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js +324 -0
  314. package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js.map +1 -0
  315. package/lib/packlets/crypto-utils/keystore/index.browser.d.ts +10 -0
  316. package/lib/packlets/crypto-utils/keystore/index.browser.d.ts.map +1 -0
  317. package/lib/packlets/crypto-utils/keystore/index.browser.js +76 -0
  318. package/lib/packlets/crypto-utils/keystore/index.browser.js.map +1 -0
  319. package/lib/packlets/crypto-utils/keystore/index.d.ts +2 -0
  320. package/lib/packlets/crypto-utils/keystore/index.d.ts.map +1 -0
  321. package/lib/packlets/crypto-utils/keystore/index.js +5 -1
  322. package/lib/packlets/crypto-utils/keystore/index.js.map +1 -0
  323. package/lib/packlets/crypto-utils/keystore/keyStore.d.ts +314 -13
  324. package/lib/packlets/crypto-utils/keystore/keyStore.d.ts.map +1 -0
  325. package/lib/packlets/crypto-utils/keystore/keyStore.js +877 -124
  326. package/lib/packlets/crypto-utils/keystore/keyStore.js.map +1 -0
  327. package/lib/packlets/crypto-utils/keystore/model.d.ts +404 -21
  328. package/lib/packlets/crypto-utils/keystore/model.d.ts.map +1 -0
  329. package/lib/packlets/crypto-utils/keystore/model.js +37 -5
  330. package/lib/packlets/crypto-utils/keystore/model.js.map +1 -0
  331. package/lib/packlets/crypto-utils/keystore/privateKeyStorage.d.ts +53 -0
  332. package/lib/packlets/crypto-utils/keystore/privateKeyStorage.d.ts.map +1 -0
  333. package/lib/packlets/crypto-utils/keystore/privateKeyStorage.js +22 -0
  334. package/lib/packlets/crypto-utils/keystore/privateKeyStorage.js.map +1 -0
  335. package/lib/packlets/crypto-utils/model.d.ts +518 -10
  336. package/lib/packlets/crypto-utils/model.d.ts.map +1 -0
  337. package/lib/packlets/crypto-utils/model.js +33 -1
  338. package/lib/packlets/crypto-utils/model.js.map +1 -0
  339. package/lib/packlets/crypto-utils/nodeCryptoProvider.d.ts +142 -2
  340. package/lib/packlets/crypto-utils/nodeCryptoProvider.d.ts.map +1 -0
  341. package/lib/packlets/crypto-utils/nodeCryptoProvider.js +346 -0
  342. package/lib/packlets/crypto-utils/nodeCryptoProvider.js.map +1 -0
  343. package/lib/packlets/crypto-utils/seedDerivedKeyPair.d.ts +42 -0
  344. package/lib/packlets/crypto-utils/seedDerivedKeyPair.d.ts.map +1 -0
  345. package/lib/packlets/crypto-utils/seedDerivedKeyPair.js +123 -0
  346. package/lib/packlets/crypto-utils/seedDerivedKeyPair.js.map +1 -0
  347. package/lib/packlets/crypto-utils/spkiHelpers.d.ts +151 -0
  348. package/lib/packlets/crypto-utils/spkiHelpers.d.ts.map +1 -0
  349. package/lib/packlets/crypto-utils/spkiHelpers.js +297 -0
  350. package/lib/packlets/crypto-utils/spkiHelpers.js.map +1 -0
  351. package/lib/packlets/csv/csvFileHelpers.d.ts +0 -10
  352. package/lib/packlets/csv/csvFileHelpers.d.ts.map +1 -0
  353. package/lib/packlets/csv/csvFileHelpers.js +0 -15
  354. package/lib/packlets/csv/csvFileHelpers.js.map +1 -0
  355. package/lib/packlets/csv/csvHelpers.d.ts +10 -0
  356. package/lib/packlets/csv/csvHelpers.d.ts.map +1 -0
  357. package/lib/packlets/csv/csvHelpers.js +15 -0
  358. package/lib/packlets/csv/csvHelpers.js.map +1 -0
  359. package/lib/packlets/csv/index.browser.d.ts +0 -1
  360. package/lib/packlets/csv/index.browser.d.ts.map +1 -0
  361. package/lib/packlets/csv/index.browser.js +1 -5
  362. package/lib/packlets/csv/index.browser.js.map +1 -0
  363. package/lib/packlets/csv/index.d.ts.map +1 -0
  364. package/lib/packlets/csv/index.js.map +1 -0
  365. package/lib/packlets/experimental/extendedArray.d.ts.map +1 -0
  366. package/lib/packlets/experimental/extendedArray.js.map +1 -0
  367. package/lib/packlets/experimental/formatter.d.ts.map +1 -0
  368. package/lib/packlets/experimental/formatter.js.map +1 -0
  369. package/lib/packlets/experimental/index.d.ts.map +1 -0
  370. package/lib/packlets/experimental/index.js.map +1 -0
  371. package/lib/packlets/experimental/rangeOf.d.ts.map +1 -0
  372. package/lib/packlets/experimental/rangeOf.js.map +1 -0
  373. package/lib/packlets/hash/index.browser.d.ts.map +1 -0
  374. package/lib/packlets/hash/index.browser.js.map +1 -0
  375. package/lib/packlets/hash/index.d.ts.map +1 -0
  376. package/lib/packlets/hash/index.js.map +1 -0
  377. package/lib/packlets/hash/index.node.d.ts.map +1 -0
  378. package/lib/packlets/hash/index.node.js.map +1 -0
  379. package/lib/packlets/hash/md5Normalizer.browser.d.ts.map +1 -0
  380. package/lib/packlets/hash/md5Normalizer.browser.js.map +1 -0
  381. package/lib/packlets/hash/md5Normalizer.d.ts.map +1 -0
  382. package/lib/packlets/hash/md5Normalizer.js.map +1 -0
  383. package/lib/packlets/mustache/index.d.ts +1 -1
  384. package/lib/packlets/mustache/index.d.ts.map +1 -0
  385. package/lib/packlets/mustache/index.js.map +1 -0
  386. package/lib/packlets/mustache/interfaces.d.ts +34 -0
  387. package/lib/packlets/mustache/interfaces.d.ts.map +1 -0
  388. package/lib/packlets/mustache/interfaces.js.map +1 -0
  389. package/lib/packlets/mustache/mustacheTemplate.d.ts +2 -0
  390. package/lib/packlets/mustache/mustacheTemplate.d.ts.map +1 -0
  391. package/lib/packlets/mustache/mustacheTemplate.js +42 -4
  392. package/lib/packlets/mustache/mustacheTemplate.js.map +1 -0
  393. package/lib/packlets/record-jar/index.browser.d.ts +0 -1
  394. package/lib/packlets/record-jar/index.browser.d.ts.map +1 -0
  395. package/lib/packlets/record-jar/index.browser.js +1 -5
  396. package/lib/packlets/record-jar/index.browser.js.map +1 -0
  397. package/lib/packlets/record-jar/index.d.ts.map +1 -0
  398. package/lib/packlets/record-jar/index.js.map +1 -0
  399. package/lib/packlets/record-jar/recordJarFileHelpers.d.ts +0 -11
  400. package/lib/packlets/record-jar/recordJarFileHelpers.d.ts.map +1 -0
  401. package/lib/packlets/record-jar/recordJarFileHelpers.js +0 -19
  402. package/lib/packlets/record-jar/recordJarFileHelpers.js.map +1 -0
  403. package/lib/packlets/record-jar/recordJarHelpers.d.ts +11 -0
  404. package/lib/packlets/record-jar/recordJarHelpers.d.ts.map +1 -0
  405. package/lib/packlets/record-jar/recordJarHelpers.js +19 -0
  406. package/lib/packlets/record-jar/recordJarHelpers.js.map +1 -0
  407. package/lib/packlets/safer-fetch/addressClassification.d.ts +144 -0
  408. package/lib/packlets/safer-fetch/addressClassification.d.ts.map +1 -0
  409. package/lib/packlets/safer-fetch/addressClassification.js +441 -0
  410. package/lib/packlets/safer-fetch/addressClassification.js.map +1 -0
  411. package/lib/packlets/safer-fetch/addressPolicy.d.ts +113 -0
  412. package/lib/packlets/safer-fetch/addressPolicy.d.ts.map +1 -0
  413. package/lib/packlets/safer-fetch/addressPolicy.js +123 -0
  414. package/lib/packlets/safer-fetch/addressPolicy.js.map +1 -0
  415. package/lib/packlets/safer-fetch/contentType.d.ts +51 -0
  416. package/lib/packlets/safer-fetch/contentType.d.ts.map +1 -0
  417. package/lib/packlets/safer-fetch/contentType.js +127 -0
  418. package/lib/packlets/safer-fetch/contentType.js.map +1 -0
  419. package/lib/packlets/safer-fetch/deadline.d.ts +138 -0
  420. package/lib/packlets/safer-fetch/deadline.d.ts.map +1 -0
  421. package/lib/packlets/safer-fetch/deadline.js +258 -0
  422. package/lib/packlets/safer-fetch/deadline.js.map +1 -0
  423. package/lib/packlets/safer-fetch/defaults.d.ts +108 -0
  424. package/lib/packlets/safer-fetch/defaults.d.ts.map +1 -0
  425. package/lib/packlets/safer-fetch/defaults.js +134 -0
  426. package/lib/packlets/safer-fetch/defaults.js.map +1 -0
  427. package/lib/packlets/safer-fetch/failureReason.d.ts +148 -0
  428. package/lib/packlets/safer-fetch/failureReason.d.ts.map +1 -0
  429. package/lib/packlets/safer-fetch/failureReason.js +22 -0
  430. package/lib/packlets/safer-fetch/failureReason.js.map +1 -0
  431. package/lib/packlets/safer-fetch/guards.d.ts +62 -0
  432. package/lib/packlets/safer-fetch/guards.d.ts.map +1 -0
  433. package/lib/packlets/safer-fetch/guards.js +153 -0
  434. package/lib/packlets/safer-fetch/guards.js.map +1 -0
  435. package/lib/packlets/safer-fetch/index.browser.d.ts +33 -0
  436. package/lib/packlets/safer-fetch/index.browser.d.ts.map +1 -0
  437. package/lib/packlets/safer-fetch/index.browser.js +82 -0
  438. package/lib/packlets/safer-fetch/index.browser.js.map +1 -0
  439. package/lib/packlets/safer-fetch/index.d.ts +27 -0
  440. package/lib/packlets/safer-fetch/index.d.ts.map +1 -0
  441. package/lib/packlets/safer-fetch/index.js +78 -0
  442. package/lib/packlets/safer-fetch/index.js.map +1 -0
  443. package/lib/packlets/safer-fetch/model.d.ts +373 -0
  444. package/lib/packlets/safer-fetch/model.d.ts.map +1 -0
  445. package/lib/packlets/safer-fetch/model.js +22 -0
  446. package/lib/packlets/safer-fetch/model.js.map +1 -0
  447. package/lib/packlets/safer-fetch/nodeAddressGuard.d.ts +129 -0
  448. package/lib/packlets/safer-fetch/nodeAddressGuard.d.ts.map +1 -0
  449. package/lib/packlets/safer-fetch/nodeAddressGuard.js +196 -0
  450. package/lib/packlets/safer-fetch/nodeAddressGuard.js.map +1 -0
  451. package/lib/packlets/safer-fetch/redirect.d.ts +62 -0
  452. package/lib/packlets/safer-fetch/redirect.d.ts.map +1 -0
  453. package/lib/packlets/safer-fetch/redirect.js +98 -0
  454. package/lib/packlets/safer-fetch/redirect.js.map +1 -0
  455. package/lib/packlets/safer-fetch/retry.d.ts +162 -0
  456. package/lib/packlets/safer-fetch/retry.d.ts.map +1 -0
  457. package/lib/packlets/safer-fetch/retry.js +197 -0
  458. package/lib/packlets/safer-fetch/retry.js.map +1 -0
  459. package/lib/packlets/safer-fetch/saferFetch.d.ts +108 -0
  460. package/lib/packlets/safer-fetch/saferFetch.d.ts.map +1 -0
  461. package/lib/packlets/safer-fetch/saferFetch.js +760 -0
  462. package/lib/packlets/safer-fetch/saferFetch.js.map +1 -0
  463. package/lib/packlets/safer-fetch/transport.d.ts +18 -0
  464. package/lib/packlets/safer-fetch/transport.d.ts.map +1 -0
  465. package/lib/packlets/safer-fetch/transport.js +53 -0
  466. package/lib/packlets/safer-fetch/transport.js.map +1 -0
  467. package/lib/packlets/yaml/converters.d.ts.map +1 -0
  468. package/lib/packlets/yaml/converters.js.map +1 -0
  469. package/lib/packlets/yaml/index.d.ts +1 -0
  470. package/lib/packlets/yaml/index.d.ts.map +1 -0
  471. package/lib/packlets/yaml/index.js +1 -0
  472. package/lib/packlets/yaml/index.js.map +1 -0
  473. package/lib/packlets/yaml/serializers.d.ts +45 -0
  474. package/lib/packlets/yaml/serializers.d.ts.map +1 -0
  475. package/lib/packlets/yaml/serializers.js +84 -0
  476. package/lib/packlets/yaml/serializers.js.map +1 -0
  477. package/lib/packlets/zip-file-tree/index.d.ts.map +1 -0
  478. package/lib/packlets/zip-file-tree/index.js.map +1 -0
  479. package/lib/packlets/zip-file-tree/zipFileTreeAccessors.d.ts +84 -8
  480. package/lib/packlets/zip-file-tree/zipFileTreeAccessors.d.ts.map +1 -0
  481. package/lib/packlets/zip-file-tree/zipFileTreeAccessors.js +99 -9
  482. package/lib/packlets/zip-file-tree/zipFileTreeAccessors.js.map +1 -0
  483. package/lib/packlets/zip-file-tree/zipFileTreeWriter.d.ts +26 -1
  484. package/lib/packlets/zip-file-tree/zipFileTreeWriter.d.ts.map +1 -0
  485. package/lib/packlets/zip-file-tree/zipFileTreeWriter.js +17 -1
  486. package/lib/packlets/zip-file-tree/zipFileTreeWriter.js.map +1 -0
  487. package/package.json +30 -15
  488. package/lib/packlets/ai-assist/apiClient.d.ts +0 -60
@@ -0,0 +1 @@
1
+ {"version":3,"file":"endpoint.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/endpoint.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAChF,+EAA+E;AAC/E,4EAA4E;AAC5E,wEAAwE;AACxE,2DAA2D;AAC3D,EAAE;AACF,iFAAiF;AACjF,kDAAkD;AAClD,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,8EAA8E;AAC9E,yEAAyE;AACzE,gFAAgF;AAChF,gFAAgF;AAChF,YAAY;AAEZ;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAU,OAAO,EAAE,MAAM,eAAe,CAAC;AAItD;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACxE,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAc;IACjD,OAAO;QACL,WAAW,EAAE,MAAM;QACnB,mBAAmB,EAAE,YAAY;QACjC,2CAA2C,EAAE,MAAM;KACpD,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC;AACtC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CACrC,UAAiC,EACjC,QAAiB;IAEjB,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,aAAa,UAAU,CAAC,EAAE,kCAAkC,CAAC,CAAC;QAC5E,CAAC;QACD,OAAO,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;IACzD,CAAC;IACD,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1D,OAAO,IAAI,CAAC,aAAa,UAAU,CAAC,EAAE,6CAA6C,CAAC,CAAC;IACvF,CAAC;IACD,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,IAAI,CAAC,aAAa,UAAU,CAAC,EAAE,gCAAgC,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAChE,OAAO,IAAI,CAAC,aAAa,UAAU,CAAC,EAAE,2CAA2C,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvG,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvD,OAAO,IAAI,CAAC,aAAa,UAAU,CAAC,EAAE,yDAAyD,CAAC,CAAC;IACnG,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7D,OAAO,IAAI,CACT,aAAa,UAAU,CAAC,EAAE,4EAA4E,CACvG,CAAC;IACJ,CAAC;IACD,uEAAuE;IACvE,wEAAwE;IACxE,sCAAsC;IACtC,OAAO,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3E,CAAC","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Helper for resolving a request's effective base URL from a provider\n * descriptor and an optional caller-supplied endpoint override.\n *\n * @packageDocumentation\n */\n\nimport { fail, Result, succeed } from '@fgv/ts-utils';\n\nimport { type IAiProviderDescriptor } from './model';\n\n/**\n * Builds an OpenAI-style `Authorization: Bearer ${key}` header, or an empty\n * record when the key is empty. Self-hosted/local OpenAI-compatible servers\n * (Ollama, LM Studio, llama.cpp) often reject `Authorization: Bearer ` with\n * an empty key, so we omit the header entirely in that case.\n *\n * @internal\n */\nexport function bearerAuthHeader(apiKey: string): Record<string, string> {\n return apiKey.length > 0 ? { Authorization: `Bearer ${apiKey}` } : {};\n}\n\n/**\n * The Anthropic Messages API auth + protocol headers.\n *\n * @remarks\n * `anthropic-version` is a **wire-protocol pin**, and single-sourcing it here is\n * the point of this helper: it was previously replicated across the completion\n * client, the list-models client and the streaming adapter, so bumping it was a\n * three-file edit with nothing to catch a miss.\n *\n * `anthropic-dangerous-direct-browser-access` is required for browser callers;\n * it is sent unconditionally because the same client code serves both runtimes.\n *\n * @internal\n */\nexport function anthropicAuthHeaders(apiKey: string): Record<string, string> {\n return {\n 'x-api-key': apiKey,\n 'anthropic-version': '2023-06-01',\n 'anthropic-dangerous-direct-browser-access': 'true'\n };\n}\n\n/**\n * The Gemini API auth header. Gemini keys ride in `x-goog-api-key` rather than\n * an `Authorization` bearer.\n * @internal\n */\nexport function geminiAuthHeader(apiKey: string): Record<string, string> {\n return { 'x-goog-api-key': apiKey };\n}\n\n/**\n * Resolves the effective base URL for a request, validating the optional\n * `endpoint` override when present. Returns the URL with any trailing slash\n * stripped so per-route suffix concatenation (e.g. `/chat/completions`)\n * produces the same shape regardless of whether the caller supplied an\n * override or the descriptor's default is used.\n *\n * @internal\n */\nexport function resolveEffectiveBaseUrl(\n descriptor: IAiProviderDescriptor,\n endpoint?: string\n): Result<string> {\n if (endpoint === undefined) {\n if (!descriptor.baseUrl) {\n return fail(`provider \"${descriptor.id}\" has no API endpoint configured`);\n }\n return succeed(descriptor.baseUrl.replace(/\\/+$/, ''));\n }\n if (typeof endpoint !== 'string' || endpoint.length === 0) {\n return fail(`provider \"${descriptor.id}\": endpoint must be a non-empty http(s) URL`);\n }\n let parsed: URL;\n try {\n parsed = new URL(endpoint);\n } catch {\n return fail(`provider \"${descriptor.id}\": endpoint is not a valid URL`);\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n return fail(`provider \"${descriptor.id}\": endpoint must use http or https (got ${parsed.protocol})`);\n }\n if (parsed.search.length > 0 || parsed.hash.length > 0) {\n return fail(`provider \"${descriptor.id}\": endpoint must not include a query string or fragment`);\n }\n if (parsed.username.length > 0 || parsed.password.length > 0) {\n return fail(\n `provider \"${descriptor.id}\": endpoint must not include userinfo; pass credentials via apiKey instead`\n );\n }\n // Reconstruct from origin + pathname so the returned URL is normalized\n // (no userinfo, no query, no fragment) and the suffix concat in callers\n // produces a well-formed request URL.\n return succeed(`${parsed.origin}${parsed.pathname}`.replace(/\\/+$/, ''));\n}\n"]}
@@ -0,0 +1,104 @@
1
+ // Copyright (c) 2026 Erik Fortune
2
+ //
3
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ // of this software and associated documentation files (the "Software"), to deal
5
+ // in the Software without restriction, including without limitation the rights
6
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ // copies of the Software, and to permit persons to whom the Software is
8
+ // furnished to do so, subject to the following conditions:
9
+ //
10
+ // The above copyright notice and this permission notice shall be included in all
11
+ // copies or substantial portions of the Software.
12
+ //
13
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ // SOFTWARE.
20
+ /**
21
+ * Shared low-level HTTP helpers for the AI-assist provider clients (completion,
22
+ * image generation, embedding). Internal to the packlet.
23
+ * @packageDocumentation
24
+ */
25
+ import { isJsonObject } from '@fgv/ts-json-base';
26
+ import { captureAsyncResult, fail, succeed } from '@fgv/ts-utils';
27
+ /**
28
+ * Issue one request and parse a JSON object body, or fail.
29
+ *
30
+ * @remarks
31
+ * The single implementation behind {@link fetchJson}, {@link fetchGetJson} and
32
+ * {@link fetchMultipart} — the three differed *only* in how they built their
33
+ * `RequestInit` and what they logged, and carried byte-identical copies of
34
+ * everything after the `fetch` call. Non-2xx responses, network errors, invalid
35
+ * JSON and non-object JSON bodies are all surfaced as `Result.fail`.
36
+ * @internal
37
+ */
38
+ async function _fetchAndParseJson(url, init, requestLabel, logger) {
39
+ /* c8 ignore next 1 - optional logger */
40
+ logger === null || logger === void 0 ? void 0 : logger.detail(`AI API request: ${requestLabel}`);
41
+ // `captureAsyncResult` normalizes both a synchronous throw and a rejected
42
+ // promise, and its `_errorMessage` is the same `instanceof Error` shaping this
43
+ // used to spell out by hand — so the failure text is unchanged and the
44
+ // defensive `c8 ignore` on the non-Error branch is no longer needed here.
45
+ const fetched = await captureAsyncResult(() => fetch(url, init)).withErrorFormat((msg) => `AI API request failed: ${msg}`);
46
+ if (fetched.isFailure()) {
47
+ /* c8 ignore next 1 - optional logger */
48
+ logger === null || logger === void 0 ? void 0 : logger.error(fetched.message);
49
+ return fail(fetched.message);
50
+ }
51
+ const response = fetched.value;
52
+ if (!response.ok) {
53
+ const errorText = await response.text().catch(() => 'unknown error');
54
+ /* c8 ignore next 1 - optional logger */
55
+ logger === null || logger === void 0 ? void 0 : logger.error(`AI API returned ${response.status}: ${errorText}`);
56
+ return fail(`AI API returned ${response.status}: ${errorText}`);
57
+ }
58
+ /* c8 ignore next 1 - optional logger */
59
+ logger === null || logger === void 0 ? void 0 : logger.detail(`AI API response: ${response.status}`);
60
+ let json;
61
+ try {
62
+ json = await response.json();
63
+ }
64
+ catch (_a) {
65
+ /* c8 ignore next 1 - optional logger */
66
+ logger === null || logger === void 0 ? void 0 : logger.error('AI API returned invalid JSON response');
67
+ return fail('AI API returned invalid JSON response');
68
+ }
69
+ if (!isJsonObject(json)) {
70
+ /* c8 ignore next 1 - optional logger */
71
+ logger === null || logger === void 0 ? void 0 : logger.error('AI API returned non-object JSON response');
72
+ return fail('AI API returned non-object JSON response');
73
+ }
74
+ return succeed(json);
75
+ }
76
+ /**
77
+ * Makes a JSON POST request and returns the parsed object body, or a failure.
78
+ * @internal
79
+ */
80
+ export async function fetchJson(url, headers, body, logger, signal) {
81
+ return _fetchAndParseJson(url, {
82
+ method: 'POST',
83
+ headers: Object.assign({ 'Content-Type': 'application/json' }, headers),
84
+ body: JSON.stringify(body),
85
+ signal
86
+ }, `POST ${url}`, logger);
87
+ }
88
+ /**
89
+ * Makes an HTTP GET request and returns the parsed JSON, or a failure.
90
+ * @internal
91
+ */
92
+ export async function fetchGetJson(url, headers, logger, signal) {
93
+ return _fetchAndParseJson(url, { method: 'GET', headers, signal }, `GET ${url}`, logger);
94
+ }
95
+ /**
96
+ * Makes a multipart/form-data POST request and returns the parsed JSON, or a
97
+ * failure. The Content-Type header (with boundary) is set automatically by
98
+ * `fetch` from the `FormData` body — callers must NOT pass it explicitly.
99
+ * @internal
100
+ */
101
+ export async function fetchMultipart(url, headers, body, logger, signal) {
102
+ return _fetchAndParseJson(url, { method: 'POST', headers, body, signal }, `POST ${url} (multipart)`, logger);
103
+ }
104
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/http.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAChF,+EAA+E;AAC/E,4EAA4E;AAC5E,wEAAwE;AACxE,2DAA2D;AAC3D,EAAE;AACF,iFAAiF;AACjF,kDAAkD;AAClD,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,8EAA8E;AAC9E,yEAAyE;AACzE,gFAAgF;AAChF,gFAAgF;AAChF,YAAY;AAEZ;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAmB,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAwB,OAAO,EAAE,MAAM,eAAe,CAAC;AAYxF;;;;;;;;;;GAUG;AACH,KAAK,UAAU,kBAAkB,CAC/B,GAAW,EACX,IAAiB,EACjB,YAAoB,EACpB,MAAwB;IAExB,wCAAwC;IACxC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,MAAM,CAAC,mBAAmB,YAAY,EAAE,CAAC,CAAC;IAElD,0EAA0E;IAC1E,+EAA+E;IAC/E,uEAAuE;IACvE,0EAA0E;IAC1E,MAAM,OAAO,GAAqB,MAAM,kBAAkB,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,eAAe,CAChG,CAAC,GAAG,EAAE,EAAE,CAAC,0BAA0B,GAAG,EAAE,CACzC,CAAC;IACF,IAAI,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;QACxB,wCAAwC;QACxC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IACD,MAAM,QAAQ,GAAa,OAAO,CAAC,KAAK,CAAC;IAEzC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC;QACrE,wCAAwC;QACxC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,CAAC,mBAAmB,QAAQ,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC,CAAC;QAClE,OAAO,IAAI,CAAC,mBAAmB,QAAQ,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,wCAAwC;IACxC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,MAAM,CAAC,oBAAoB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAEtD,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;IAAC,WAAM,CAAC;QACP,wCAAwC;QACxC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,CAAC,uCAAuC,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC,uCAAuC,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,wCAAwC;QACxC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC,0CAA0C,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;AACvB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,GAAW,EACX,OAA+B,EAC/B,IAAa,EACb,MAAwB,EACxB,MAAoB;IAEpB,OAAO,kBAAkB,CACvB,GAAG,EACH;QACE,MAAM,EAAE,MAAM;QACd,OAAO,kBAAI,cAAc,EAAE,kBAAkB,IAAK,OAAO,CAAE;QAC3D,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;QAC1B,MAAM;KACP,EACD,QAAQ,GAAG,EAAE,EACb,MAAM,CACP,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAW,EACX,OAA+B,EAC/B,MAAwB,EACxB,MAAoB;IAEpB,OAAO,kBAAkB,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;AAC3F,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAW,EACX,OAA+B,EAC/B,IAAc,EACd,MAAwB,EACxB,MAAoB;IAEpB,OAAO,kBAAkB,CACvB,GAAG,EACH,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EACzC,QAAQ,GAAG,cAAc,EACzB,MAAM,CACP,CAAC;AACJ,CAAC","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Shared low-level HTTP helpers for the AI-assist provider clients (completion,\n * image generation, embedding). Internal to the packlet.\n * @packageDocumentation\n */\n\nimport { isJsonObject, type JsonObject } from '@fgv/ts-json-base';\nimport { captureAsyncResult, fail, type Logging, Result, succeed } from '@fgv/ts-utils';\n\n/**\n * Internal API configuration built from a provider descriptor.\n * @internal\n */\nexport interface IAiApiConfig {\n readonly baseUrl: string;\n readonly apiKey: string;\n readonly model: string;\n}\n\n/**\n * Issue one request and parse a JSON object body, or fail.\n *\n * @remarks\n * The single implementation behind {@link fetchJson}, {@link fetchGetJson} and\n * {@link fetchMultipart} — the three differed *only* in how they built their\n * `RequestInit` and what they logged, and carried byte-identical copies of\n * everything after the `fetch` call. Non-2xx responses, network errors, invalid\n * JSON and non-object JSON bodies are all surfaced as `Result.fail`.\n * @internal\n */\nasync function _fetchAndParseJson(\n url: string,\n init: RequestInit,\n requestLabel: string,\n logger?: Logging.ILogger\n): Promise<Result<JsonObject>> {\n /* c8 ignore next 1 - optional logger */\n logger?.detail(`AI API request: ${requestLabel}`);\n\n // `captureAsyncResult` normalizes both a synchronous throw and a rejected\n // promise, and its `_errorMessage` is the same `instanceof Error` shaping this\n // used to spell out by hand — so the failure text is unchanged and the\n // defensive `c8 ignore` on the non-Error branch is no longer needed here.\n const fetched: Result<Response> = await captureAsyncResult(() => fetch(url, init)).withErrorFormat(\n (msg) => `AI API request failed: ${msg}`\n );\n if (fetched.isFailure()) {\n /* c8 ignore next 1 - optional logger */\n logger?.error(fetched.message);\n return fail(fetched.message);\n }\n const response: Response = fetched.value;\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'unknown error');\n /* c8 ignore next 1 - optional logger */\n logger?.error(`AI API returned ${response.status}: ${errorText}`);\n return fail(`AI API returned ${response.status}: ${errorText}`);\n }\n\n /* c8 ignore next 1 - optional logger */\n logger?.detail(`AI API response: ${response.status}`);\n\n let json: unknown;\n try {\n json = await response.json();\n } catch {\n /* c8 ignore next 1 - optional logger */\n logger?.error('AI API returned invalid JSON response');\n return fail('AI API returned invalid JSON response');\n }\n\n if (!isJsonObject(json)) {\n /* c8 ignore next 1 - optional logger */\n logger?.error('AI API returned non-object JSON response');\n return fail('AI API returned non-object JSON response');\n }\n return succeed(json);\n}\n\n/**\n * Makes a JSON POST request and returns the parsed object body, or a failure.\n * @internal\n */\nexport async function fetchJson(\n url: string,\n headers: Record<string, string>,\n body: unknown,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<JsonObject>> {\n return _fetchAndParseJson(\n url,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...headers },\n body: JSON.stringify(body),\n signal\n },\n `POST ${url}`,\n logger\n );\n}\n\n/**\n * Makes an HTTP GET request and returns the parsed JSON, or a failure.\n * @internal\n */\nexport async function fetchGetJson(\n url: string,\n headers: Record<string, string>,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<JsonObject>> {\n return _fetchAndParseJson(url, { method: 'GET', headers, signal }, `GET ${url}`, logger);\n}\n\n/**\n * Makes a multipart/form-data POST request and returns the parsed JSON, or a\n * failure. The Content-Type header (with boundary) is set automatically by\n * `fetch` from the `FormData` body — callers must NOT pass it explicitly.\n * @internal\n */\nexport async function fetchMultipart(\n url: string,\n headers: Record<string, string>,\n body: FormData,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<JsonObject>> {\n return _fetchAndParseJson(\n url,\n { method: 'POST', headers, body, signal },\n `POST ${url} (multipart)`,\n logger\n );\n}\n"]}
@@ -0,0 +1,454 @@
1
+ // Copyright (c) 2026 Erik Fortune
2
+ //
3
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ // of this software and associated documentation files (the "Software"), to deal
5
+ // in the Software without restriction, including without limitation the rights
6
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ // copies of the Software, and to permit persons to whom the Software is
8
+ // furnished to do so, subject to the following conditions:
9
+ //
10
+ // The above copyright notice and this permission notice shall be included in all
11
+ // copies or substantial portions of the Software.
12
+ //
13
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ // SOFTWARE.
20
+ import { fail, mapResults, succeed, Validators } from '@fgv/ts-utils';
21
+ import { resolveProviderModel } from './model';
22
+ import { bearerAuthHeader, geminiAuthHeader, resolveEffectiveBaseUrl } from './endpoint';
23
+ import { fetchJson, fetchMultipart } from './http';
24
+ import { resolveImageCapability, supportsImageGeneration } from './registry';
25
+ import { resolveImageOptions, validateResolvedOptions } from './imageOptionsResolver';
26
+ // ============================================================================
27
+ // Image attachment helpers
28
+ // ============================================================================
29
+ /**
30
+ * Decodes a base64-encoded image attachment into a `Blob` suitable for use as
31
+ * a multipart file field. On Node hands the `Buffer` straight to `Blob`
32
+ * (Buffer extends Uint8Array) to skip an intermediate copy; falls back to
33
+ * `atob` in browsers. Inputs come from `FileReader` or prior provider
34
+ * responses, which are trusted to be valid. Note that Node's
35
+ * `Buffer.from(..., 'base64')` silently strips invalid characters rather
36
+ * than throwing, so failures are only observable in the browser path.
37
+ * @internal
38
+ */
39
+ function attachmentToBlob(attachment) {
40
+ if (typeof Buffer !== 'undefined') {
41
+ return succeed(new Blob([Buffer.from(attachment.base64, 'base64')], { type: attachment.mimeType }));
42
+ }
43
+ /* c8 ignore start - Browser-only fallback cannot be tested in Node.js environment */
44
+ try {
45
+ const binary = atob(attachment.base64);
46
+ const bytes = new Uint8Array(binary.length);
47
+ for (let i = 0; i < binary.length; i++) {
48
+ bytes[i] = binary.charCodeAt(i);
49
+ }
50
+ return succeed(new Blob([bytes], { type: attachment.mimeType }));
51
+ }
52
+ catch (e) {
53
+ const message = e instanceof Error ? e.message : String(e);
54
+ return fail(`Invalid base64: ${message}`);
55
+ }
56
+ /* c8 ignore stop */
57
+ }
58
+ /**
59
+ * Maps a MIME type to a sensible file extension for multipart filenames.
60
+ * @internal
61
+ */
62
+ function extensionForMimeType(mimeType) {
63
+ switch (mimeType) {
64
+ case 'image/png':
65
+ return 'png';
66
+ case 'image/jpeg':
67
+ case 'image/jpg':
68
+ return 'jpg';
69
+ case 'image/webp':
70
+ return 'webp';
71
+ case 'image/gif':
72
+ return 'gif';
73
+ default:
74
+ return 'bin';
75
+ }
76
+ }
77
+ const openAiImageItem = Validators.object({
78
+ b64_json: Validators.string,
79
+ revised_prompt: Validators.string.optional()
80
+ });
81
+ const openAiImageResponse = Validators.object({
82
+ data: Validators.arrayOf(openAiImageItem).withConstraint((arr) => arr.length > 0)
83
+ });
84
+ const geminiImageInlineData = Validators.object({
85
+ mimeType: Validators.string,
86
+ data: Validators.string
87
+ });
88
+ const geminiImageOutPart = Validators.object({
89
+ text: Validators.string.optional(),
90
+ inlineData: geminiImageInlineData.optional()
91
+ });
92
+ const geminiImageOutContent = Validators.object({
93
+ parts: Validators.arrayOf(geminiImageOutPart)
94
+ });
95
+ const geminiImageOutCandidate = Validators.object({
96
+ content: geminiImageOutContent.optional(),
97
+ finishReason: Validators.string.optional(),
98
+ finishMessage: Validators.string.optional()
99
+ });
100
+ const geminiImageOutResponse = Validators.object({
101
+ candidates: Validators.arrayOf(geminiImageOutCandidate).withConstraint((arr) => arr.length > 0)
102
+ });
103
+ // ---- Proxied image generation response ----
104
+ const proxiedGeneratedImage = Validators.object({
105
+ mimeType: Validators.string,
106
+ base64: Validators.string,
107
+ revisedPrompt: Validators.string.optional()
108
+ });
109
+ const proxiedImageGenerationResponse = Validators.object({
110
+ images: Validators.arrayOf(proxiedGeneratedImage).withConstraint((arr) => arr.length > 0)
111
+ });
112
+ // ============================================================================
113
+ // Image generation — adapters
114
+ // ============================================================================
115
+ /** Routes to /images/generations or /images/edits; handles outputParamStyle. @internal */
116
+ async function callOpenAiImageGeneration(config, request, capability, resolved, logger, signal) {
117
+ var _a, _b;
118
+ const refs = (_a = request.referenceImages) !== null && _a !== void 0 ? _a : [];
119
+ const headers = bearerAuthHeader(config.apiKey);
120
+ const effectiveMimeType = resolved.outputFormat !== undefined
121
+ ? `image/${resolved.outputFormat}`
122
+ : (_b = capability.defaultOutputMimeType) !== null && _b !== void 0 ? _b : 'image/png';
123
+ const fetched = refs.length > 0
124
+ ? await callOpenAiImagesEdits(config, capability, request, headers, resolved, logger, signal)
125
+ : await callOpenAiImagesGenerations(config, request, headers, resolved, capability, logger, signal);
126
+ return fetched.onSuccess((json) => openAiImageResponse
127
+ .validate(json)
128
+ .withErrorFormat((msg) => `OpenAI images API response: ${msg}`)
129
+ .onSuccess((response) => succeed({
130
+ images: response.data.map((item) => (Object.assign({ mimeType: effectiveMimeType, base64: item.b64_json }, (item.revised_prompt !== undefined ? { revisedPrompt: item.revised_prompt } : {}))))
131
+ })));
132
+ }
133
+ /** Builds the JSON /images/generations request; handles outputParamStyle. @internal */
134
+ function callOpenAiImagesGenerations(config, request, headers, resolved, capability, logger, signal) {
135
+ var _a;
136
+ const body = {
137
+ model: config.model,
138
+ prompt: request.prompt,
139
+ n: resolved.n
140
+ };
141
+ // Output format param — conditional on model capability
142
+ if (capability.outputParamStyle === 'response-format') {
143
+ body.response_format = 'b64_json';
144
+ }
145
+ else if (capability.outputParamStyle === 'output-format') {
146
+ body.output_format = (_a = resolved.outputFormat) !== null && _a !== void 0 ? _a : 'png';
147
+ }
148
+ if (resolved.size !== undefined) {
149
+ body.size = resolved.size;
150
+ }
151
+ if (capability.supportsQualityParam && resolved.quality !== undefined) {
152
+ body.quality = resolved.quality;
153
+ }
154
+ if (resolved.seed !== undefined) {
155
+ body.seed = resolved.seed;
156
+ }
157
+ if (resolved.background !== undefined) {
158
+ body.background = resolved.background;
159
+ }
160
+ if (resolved.moderation !== undefined) {
161
+ body.moderation = resolved.moderation;
162
+ }
163
+ if (resolved.outputCompression !== undefined) {
164
+ body.output_compression = resolved.outputCompression;
165
+ }
166
+ if (resolved.otherParams !== undefined) {
167
+ Object.assign(body, resolved.otherParams);
168
+ }
169
+ /* c8 ignore next 1 - optional logger */
170
+ logger === null || logger === void 0 ? void 0 : logger.info(`Image generation: model=${config.model}, n=${resolved.n}`);
171
+ return fetchJson(`${config.baseUrl}/images/generations`, headers, body, logger, signal);
172
+ }
173
+ /** Builds the multipart /images/edits request with ref images. @internal */
174
+ async function callOpenAiImagesEdits(config, capability, request, headers, resolved, logger, signal) {
175
+ const refs = request.referenceImages; // callers verify refs.length > 0 before calling this function
176
+ const blobsResult = mapResults(refs.map((ref, i) => attachmentToBlob(ref).withErrorFormat((msg) => `reference image ${i}: ${msg}`)));
177
+ /* c8 ignore next 3 - decode failure unreachable via Node's Buffer.from (silently strips invalid input) */
178
+ if (blobsResult.isFailure()) {
179
+ return fail(blobsResult.message);
180
+ }
181
+ const form = new FormData();
182
+ form.append('model', config.model);
183
+ form.append('prompt', request.prompt);
184
+ form.append('n', String(resolved.n));
185
+ if (capability.outputParamStyle !== 'output-format') {
186
+ form.append('response_format', 'b64_json');
187
+ }
188
+ if (resolved.size !== undefined) {
189
+ form.append('size', resolved.size);
190
+ }
191
+ blobsResult.value.forEach((blob, i) => {
192
+ form.append('image[]', blob, `ref-${i}.${extensionForMimeType(refs[i].mimeType)}`);
193
+ });
194
+ /* c8 ignore next 1 - optional logger */
195
+ logger === null || logger === void 0 ? void 0 : logger.info(`Image edit: model=${config.model}, n=${resolved.n}, refs=${refs.length}`);
196
+ return fetchMultipart(`${config.baseUrl}/images/edits`, headers, form, logger, signal);
197
+ }
198
+ /** Calls xAI /images/edits with JSON body (not multipart); up to 3 source images. @internal */
199
+ async function callXaiImagesEdits(config, request, resolved, logger, signal) {
200
+ var _a;
201
+ /* c8 ignore next 1 - defensive: referenceImages always defined when this function is called */
202
+ const refs = (_a = request.referenceImages) !== null && _a !== void 0 ? _a : [];
203
+ if (refs.length > 3) {
204
+ return fail(`xAI image edits supports at most 3 reference images; got ${refs.length}`);
205
+ }
206
+ const images = refs.map((ref) => ({
207
+ type: 'image_url',
208
+ url: `data:${ref.mimeType};base64,${ref.base64}`
209
+ }));
210
+ const body = {
211
+ model: config.model,
212
+ prompt: request.prompt,
213
+ n: resolved.n,
214
+ response_format: 'b64_json',
215
+ image: images
216
+ };
217
+ if (resolved.aspectRatio !== undefined) {
218
+ body.aspect_ratio = resolved.aspectRatio;
219
+ }
220
+ if (resolved.resolution !== undefined) {
221
+ body.resolution = resolved.resolution;
222
+ }
223
+ if (resolved.otherParams !== undefined) {
224
+ Object.assign(body, resolved.otherParams);
225
+ }
226
+ /* c8 ignore next 1 - optional logger */
227
+ logger === null || logger === void 0 ? void 0 : logger.info(`xAI image edit: model=${config.model}, n=${resolved.n}, refs=${refs.length}`);
228
+ return fetchJson(`${config.baseUrl}/images/edits`, bearerAuthHeader(config.apiKey), body, logger, signal);
229
+ }
230
+ /**
231
+ * Normalizes an xAI images API response (OpenAI-shaped) into the provider-neutral
232
+ * generated-image result.
233
+ *
234
+ * @remarks
235
+ * Shared by the generations path and the edits path. These were two independent
236
+ * copies 160 lines apart — identical but for the receiver name — so the
237
+ * `defaultOutputMimeType` fallback and the error prefix each existed twice, and a
238
+ * fix to one would silently have missed the other.
239
+ * @internal
240
+ */
241
+ function normalizeXaiImageResponse(json, capability) {
242
+ return openAiImageResponse
243
+ .validate(json)
244
+ .withErrorFormat((msg) => `xAI images API response: ${msg}`)
245
+ .onSuccess((response) => succeed({
246
+ images: response.data.map((item) => {
247
+ var _a;
248
+ return ({
249
+ mimeType: (_a = capability.defaultOutputMimeType) !== null && _a !== void 0 ? _a : 'image/jpeg',
250
+ base64: item.b64_json
251
+ });
252
+ })
253
+ }));
254
+ }
255
+ /** Calls xAI /images/generations; uses aspect_ratio instead of size. @internal */
256
+ async function callXaiImageGeneration(config, request, capability, resolved, logger, signal) {
257
+ const headers = bearerAuthHeader(config.apiKey);
258
+ const body = {
259
+ model: config.model,
260
+ prompt: request.prompt,
261
+ n: resolved.n,
262
+ response_format: 'b64_json'
263
+ };
264
+ if (resolved.aspectRatio !== undefined) {
265
+ body.aspect_ratio = resolved.aspectRatio;
266
+ }
267
+ if (resolved.resolution !== undefined) {
268
+ body.resolution = resolved.resolution;
269
+ }
270
+ if (resolved.otherParams !== undefined) {
271
+ Object.assign(body, resolved.otherParams);
272
+ }
273
+ /* c8 ignore next 1 - optional logger */
274
+ logger === null || logger === void 0 ? void 0 : logger.info(`xAI image generation: model=${config.model}, n=${resolved.n}`);
275
+ const fetched = await fetchJson(`${config.baseUrl}/images/generations`, headers, body, logger, signal);
276
+ return fetched.onSuccess((json) => normalizeXaiImageResponse(json, capability));
277
+ }
278
+ /**
279
+ * Gemini `finishReason` values that indicate a normal terminal completion rather
280
+ * than a refusal. `STOP` is set on every successful generation (and on completions
281
+ * that return a text part instead of an image); `MAX_TOKENS` is a benign truncation.
282
+ * A candidate carrying only one of these is NOT a decline — treating it as one would
283
+ * mislabel an ordinary no-image outcome as a policy refusal. @internal
284
+ */
285
+ const benignGeminiImageFinishReasons = new Set(['STOP', 'MAX_TOKENS']);
286
+ /** Calls Gemini :generateContent for image output; accepts ref images as inlineData. @internal */
287
+ async function callGeminiImageOutGeneration(config, request, resolved, logger, signal) {
288
+ var _a;
289
+ const url = `${config.baseUrl}/models/${config.model}:generateContent`;
290
+ const refs = (_a = request.referenceImages) !== null && _a !== void 0 ? _a : [];
291
+ const parts = [{ text: request.prompt }];
292
+ for (const ref of refs) {
293
+ parts.push({ inlineData: { mimeType: ref.mimeType, data: ref.base64 } });
294
+ }
295
+ const generationConfig = {};
296
+ if (resolved.geminiAspectRatio !== undefined) {
297
+ generationConfig.imageConfig = { aspectRatio: resolved.geminiAspectRatio };
298
+ }
299
+ if (resolved.otherParams !== undefined) {
300
+ Object.assign(generationConfig, resolved.otherParams);
301
+ }
302
+ const body = { contents: [{ role: 'user', parts }] };
303
+ if (Object.keys(generationConfig).length > 0) {
304
+ body.generationConfig = generationConfig;
305
+ }
306
+ const headers = geminiAuthHeader(config.apiKey);
307
+ /* c8 ignore next 1 - optional logger */
308
+ logger === null || logger === void 0 ? void 0 : logger.info(`Gemini image-out: model=${config.model}, refs=${refs.length}`);
309
+ return (await fetchJson(url, headers, body, logger, signal)).onSuccess((json) => geminiImageOutResponse
310
+ .validate(json)
311
+ .withErrorFormat((msg) => `Gemini image API response: ${msg}`)
312
+ .onSuccess((response) => {
313
+ var _a, _b;
314
+ const images = [];
315
+ for (const candidate of response.candidates) {
316
+ for (const part of (_b = (_a = candidate.content) === null || _a === void 0 ? void 0 : _a.parts) !== null && _b !== void 0 ? _b : []) {
317
+ if (part.inlineData) {
318
+ images.push({
319
+ mimeType: part.inlineData.mimeType,
320
+ base64: part.inlineData.data
321
+ });
322
+ }
323
+ }
324
+ }
325
+ if (images.length === 0) {
326
+ // A candidate with no image parts is a *decline* only when it carries a
327
+ // refusal-shaped finishReason — i.e. present and not a benign terminal reason
328
+ // (`STOP`/`MAX_TOKENS`). A normal completion that emitted text-instead-of-image
329
+ // carries `finishReason: 'STOP'` and must fall through to the no-image message.
330
+ const declined = response.candidates.find((candidate) => candidate.finishReason !== undefined &&
331
+ !benignGeminiImageFinishReasons.has(candidate.finishReason));
332
+ if ((declined === null || declined === void 0 ? void 0 : declined.finishReason) !== undefined) {
333
+ // Truthiness (not `!== undefined`) so an empty-string finishMessage is treated
334
+ // as "no message" and produces no dangling ` — ` separator.
335
+ const suffix = declined.finishMessage ? ` — ${declined.finishMessage}` : '';
336
+ return fail(`Gemini image generation declined: ${declined.finishReason}${suffix}`);
337
+ }
338
+ return fail('Gemini image API response: no image parts in response');
339
+ }
340
+ return succeed({ images });
341
+ }));
342
+ }
343
+ // ============================================================================
344
+ // Image generation — dispatcher
345
+ // ============================================================================
346
+ /**
347
+ * Calls the appropriate image-generation API for a given provider. Routes by the
348
+ * `format` field of the resolved {@link IAiImageModelCapability}:
349
+ * `'openai-images'`, `'xai-images'`, `'xai-images-edits'`, or
350
+ * `'gemini-image-out'`. Rejects up front if `referenceImages` is set but the
351
+ * capability does not declare `acceptsImageReferenceInput`.
352
+ * @param params - Request parameters including descriptor, API key, and prompt
353
+ * @public
354
+ */
355
+ export async function callProviderImageGeneration(params) {
356
+ var _a, _b, _c;
357
+ const { descriptor, apiKey, params: request, modelOverride, logger, signal, endpoint } = params;
358
+ if (!supportsImageGeneration(descriptor)) {
359
+ return fail(`provider "${descriptor.id}" does not support image generation`);
360
+ }
361
+ const baseUrlResult = resolveEffectiveBaseUrl(descriptor, endpoint);
362
+ if (baseUrlResult.isFailure()) {
363
+ return fail(baseUrlResult.message);
364
+ }
365
+ const modelResult = resolveProviderModel(descriptor, modelOverride, 'image');
366
+ if (modelResult.isFailure()) {
367
+ return fail(modelResult.message);
368
+ }
369
+ const model = modelResult.value;
370
+ const capability = resolveImageCapability(descriptor, model);
371
+ if (capability === undefined) {
372
+ return fail(`provider "${descriptor.id}" does not support image generation for model "${model}"`);
373
+ }
374
+ if (((_b = (_a = request.referenceImages) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0 && !capability.acceptsImageReferenceInput) {
375
+ return fail(`model "${model}" does not support reference images`);
376
+ }
377
+ const resolved = resolveImageOptions(model, capability, request.options);
378
+ const validationResult = validateResolvedOptions(model, capability, resolved);
379
+ if (validationResult.isFailure()) {
380
+ return fail(validationResult.message);
381
+ }
382
+ const config = {
383
+ baseUrl: baseUrlResult.value,
384
+ apiKey,
385
+ model
386
+ };
387
+ /* c8 ignore next 6 - optional logger diagnostic output */
388
+ if (logger) {
389
+ logger.info(`AI image generation: provider=${descriptor.id}, format=${capability.format}, ` +
390
+ `model=${config.model}`);
391
+ }
392
+ switch (capability.format) {
393
+ case 'openai-images':
394
+ return callOpenAiImageGeneration(config, request, capability, resolved, logger, signal);
395
+ case 'xai-images':
396
+ return callXaiImageGeneration(config, request, capability, resolved, logger, signal);
397
+ case 'xai-images-edits': {
398
+ const refs = (_c = request.referenceImages) !== null && _c !== void 0 ? _c : [];
399
+ if (refs.length > 0) {
400
+ const editsResult = await callXaiImagesEdits(config, request, resolved, logger, signal);
401
+ return editsResult.onSuccess((json) => normalizeXaiImageResponse(json, capability));
402
+ }
403
+ return callXaiImageGeneration(config, request, capability, resolved, logger, signal);
404
+ }
405
+ case 'gemini-image-out':
406
+ return callGeminiImageOutGeneration(config, request, resolved, logger, signal);
407
+ /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */
408
+ default: {
409
+ const _exhaustive = capability.format;
410
+ return fail(`unsupported image API format: ${String(_exhaustive)}`);
411
+ }
412
+ }
413
+ }
414
+ // ============================================================================
415
+ // Proxied image generation
416
+ // ============================================================================
417
+ /**
418
+ * Calls the image-generation endpoint on a proxy server instead of calling
419
+ * the provider API directly from the browser.
420
+ * Endpoint: `POST ${proxyUrl}/api/ai/image-generation`. Request body:
421
+ * `{providerId, apiKey, params, modelOverride?}`. The proxy handles descriptor
422
+ * lookup, model resolution, provider dispatch, and response normalization
423
+ * (including repackaging `referenceImages` for the upstream wire format).
424
+ * Error body `{error: string}` is surfaced as `proxy: ${error}`.
425
+ * @param proxyUrl - Base URL of the proxy server
426
+ * @param params - Same parameters as {@link callProviderImageGeneration}
427
+ * @public
428
+ */
429
+ export async function callProxiedImageGeneration(proxyUrl, params) {
430
+ const { descriptor, apiKey, params: request, modelOverride, logger, signal } = params;
431
+ const body = {
432
+ providerId: descriptor.id,
433
+ apiKey,
434
+ params: request
435
+ };
436
+ if (modelOverride !== undefined) {
437
+ body.modelOverride = modelOverride;
438
+ }
439
+ /* c8 ignore next 1 - optional logger */
440
+ logger === null || logger === void 0 ? void 0 : logger.info(`AI image proxy request: provider=${descriptor.id}, proxy=${proxyUrl}`);
441
+ const url = `${proxyUrl}/api/ai/image-generation`;
442
+ const jsonResult = await fetchJson(url, {}, body, logger, signal);
443
+ if (jsonResult.isFailure()) {
444
+ return fail(jsonResult.message);
445
+ }
446
+ const response = jsonResult.value;
447
+ if (typeof response.error === 'string') {
448
+ return fail(`proxy: ${response.error}`);
449
+ }
450
+ return proxiedImageGenerationResponse
451
+ .validate(response)
452
+ .withErrorFormat((msg) => `proxy returned invalid response: ${msg}`);
453
+ }
454
+ //# sourceMappingURL=imageGenerationClient.js.map