@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,134 @@
1
+ "use strict";
2
+ // Copyright (c) 2026 Erik Fortune
3
+ //
4
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ // of this software and associated documentation files (the "Software"), to deal
6
+ // in the Software without restriction, including without limitation the rights
7
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ // copies of the Software, and to permit persons to whom the Software is
9
+ // furnished to do so, subject to the following conditions:
10
+ //
11
+ // The above copyright notice and this permission notice shall be included in all
12
+ // copies or substantial portions of the Software.
13
+ //
14
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ // SOFTWARE.
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.IDEMPOTENT_METHODS = exports.RETRY_AFTER_STATUSES = exports.RETRYABLE_HTTP_STATUSES = exports.DEFAULT_RETRY_MAX_DELAY_MS = exports.DEFAULT_RETRY_BASE_DELAY_MS = exports.SUPPORTED_SCHEMES = exports.ALWAYS_STRIPPED_HEADERS = exports.DEFAULT_MAX_REDIRECTS = exports.REDIRECT_STATUSES = exports.DEFAULT_MAX_RESPONSE_BYTES = exports.DEFAULT_HEADERS_TIMEOUT_MS = exports.DEFAULT_TIMEOUT_MS = void 0;
23
+ /**
24
+ * Default overall deadline, in milliseconds — comfortably above a slow-but-real API and far
25
+ * below "a hung request pins a socket for minutes". Streaming LLM calls should not use this
26
+ * primitive at all; that is what `AiAssist` is for.
27
+ * @public
28
+ */
29
+ exports.DEFAULT_TIMEOUT_MS = 30000;
30
+ /**
31
+ * Default deadline to first response headers, in milliseconds. A host that has not sent
32
+ * headers in ten seconds is not answering.
33
+ * @public
34
+ */
35
+ exports.DEFAULT_HEADERS_TIMEOUT_MS = 10000;
36
+ /**
37
+ * Default cap on decoded response bytes (5 MiB) — roughly an order of magnitude above a
38
+ * realistic JSON API response and well below a size that threatens a Node heap.
39
+ *
40
+ * @remarks
41
+ * Raising it is a per-call option, not a construction-time setting, precisely because real
42
+ * documents clear this. See `ISaferFetchOptions.maxResponseBytes`.
43
+ * @public
44
+ */
45
+ exports.DEFAULT_MAX_RESPONSE_BYTES = 5 * 1024 * 1024;
46
+ /**
47
+ * Redirect statuses this primitive recognizes as redirects. Other 3xx statuses (`300`, `304`,
48
+ * …) do not direct the client at a new URL and are reported as ordinary non-2xx responses.
49
+ * @public
50
+ */
51
+ exports.REDIRECT_STATUSES = [301, 302, 303, 307, 308];
52
+ /**
53
+ * Default cap on redirect hops followed under `'validate-each-hop'`.
54
+ *
55
+ * @remarks
56
+ * Five is enough for the ordinary shortener-then-canonicalize-then-CDN chains real services
57
+ * produce and small enough that a chain designed to burn budget is refused quickly. Every hop
58
+ * costs a full guard evaluation — including a DNS resolution — against the same overall
59
+ * deadline, so the cap bounds work, not just politeness.
60
+ * @public
61
+ */
62
+ exports.DEFAULT_MAX_REDIRECTS = 5;
63
+ /**
64
+ * Header names dropped on every cross-origin redirect hop, whatever the caller configured.
65
+ *
66
+ * @remarks
67
+ * Turning on manual redirects makes this primitive responsible for a rule the platform was
68
+ * applying for free: browsers and `curl` both strip credential headers when a redirect leaves
69
+ * the origin, and a hand-rolled loop that replays them hands `Authorization: Bearer …` to
70
+ * whatever host the redirect names. Callers add their own names with
71
+ * `ISaferFetchOptions.sensitiveHeaders`; these three are not removable.
72
+ * @public
73
+ */
74
+ exports.ALWAYS_STRIPPED_HEADERS = [
75
+ 'authorization',
76
+ 'cookie',
77
+ 'proxy-authorization'
78
+ ];
79
+ /**
80
+ * URL schemes this primitive will ever request.
81
+ *
82
+ * @remarks
83
+ * Core rejects everything else — `file:`, `data:`, `blob:`, `ftp:`, `gopher:`, `ws:` — outright
84
+ * and at every hop, because none of them is a legitimate network fetch and each is a standard
85
+ * SSRF payload. Deciding between `http:` and `https:`, and which ports are acceptable, belongs
86
+ * to the address guard, which is why core does not narrow this further.
87
+ * @public
88
+ */
89
+ exports.SUPPORTED_SCHEMES = ['http:', 'https:'];
90
+ /**
91
+ * Default base delay for {@link SaferFetch.IRetryPolicy | retry} backoff, in milliseconds.
92
+ * @public
93
+ */
94
+ exports.DEFAULT_RETRY_BASE_DELAY_MS = 250;
95
+ /**
96
+ * Default ceiling on a single {@link SaferFetch.IRetryPolicy | retry} delay, in milliseconds.
97
+ *
98
+ * @remarks
99
+ * It bounds the computed backoff **and** a server-supplied `Retry-After`. That second role is
100
+ * the security-relevant one: `Retry-After` is a header an attacker-controlled server chooses
101
+ * freely, so an unclamped `Retry-After: 86400` is a denial of service on the caller.
102
+ * @public
103
+ */
104
+ exports.DEFAULT_RETRY_MAX_DELAY_MS = 5000;
105
+ /**
106
+ * HTTP statuses a {@link SaferFetch.IRetryPolicy | retry policy} will retry.
107
+ *
108
+ * @remarks
109
+ * Every other status — including every other 4xx — is terminal. A `401`, a `403` and a `404`
110
+ * mean the same thing on the second attempt as on the first, and retrying them turns a client
111
+ * bug into load against a service that already said no.
112
+ * @public
113
+ */
114
+ exports.RETRYABLE_HTTP_STATUSES = [408, 429, 500, 502, 503, 504];
115
+ /**
116
+ * Statuses whose `Retry-After` header is honored.
117
+ *
118
+ * @remarks
119
+ * `429` and `503` are the two the header is specified for and the two where it carries real
120
+ * scheduling information. Honoring it on a `500` would let any failing endpoint dictate the
121
+ * caller's schedule for no benefit.
122
+ * @public
123
+ */
124
+ exports.RETRY_AFTER_STATUSES = [429, 503];
125
+ /**
126
+ * Methods retried without an explicit opt-in.
127
+ *
128
+ * @remarks
129
+ * A timeout does not tell you whether the server processed the request, so a retried `POST`
130
+ * can double-charge. `retryNonIdempotent` opts out, per call, visibly.
131
+ * @public
132
+ */
133
+ exports.IDEMPOTENT_METHODS = ['GET', 'HEAD'];
134
+ //# sourceMappingURL=defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../../src/packlets/safer-fetch/defaults.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;AACU,QAAA,kBAAkB,GAAW,KAAM,CAAC;AAEjD;;;;GAIG;AACU,QAAA,0BAA0B,GAAW,KAAM,CAAC;AAEzD;;;;;;;;GAQG;AACU,QAAA,0BAA0B,GAAW,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAElE;;;;GAIG;AACU,QAAA,iBAAiB,GAA0B,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAElF;;;;;;;;;GASG;AACU,QAAA,qBAAqB,GAAW,CAAC,CAAC;AAE/C;;;;;;;;;;GAUG;AACU,QAAA,uBAAuB,GAA0B;IAC5D,eAAe;IACf,QAAQ;IACR,qBAAqB;CACtB,CAAC;AAEF;;;;;;;;;GASG;AACU,QAAA,iBAAiB,GAA0B,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAE5E;;;GAGG;AACU,QAAA,2BAA2B,GAAW,GAAG,CAAC;AAEvD;;;;;;;;GAQG;AACU,QAAA,0BAA0B,GAAW,IAAK,CAAC;AAExD;;;;;;;;GAQG;AACU,QAAA,uBAAuB,GAA0B,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAE7F;;;;;;;;GAQG;AACU,QAAA,oBAAoB,GAA0B,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAEtE;;;;;;;GAOG;AACU,QAAA,kBAAkB,GAA0B,CAAC,KAAK,EAAE,MAAM,CAAC,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 * Default overall deadline, in milliseconds — comfortably above a slow-but-real API and far\n * below \"a hung request pins a socket for minutes\". Streaming LLM calls should not use this\n * primitive at all; that is what `AiAssist` is for.\n * @public\n */\nexport const DEFAULT_TIMEOUT_MS: number = 30_000;\n\n/**\n * Default deadline to first response headers, in milliseconds. A host that has not sent\n * headers in ten seconds is not answering.\n * @public\n */\nexport const DEFAULT_HEADERS_TIMEOUT_MS: number = 10_000;\n\n/**\n * Default cap on decoded response bytes (5 MiB) — roughly an order of magnitude above a\n * realistic JSON API response and well below a size that threatens a Node heap.\n *\n * @remarks\n * Raising it is a per-call option, not a construction-time setting, precisely because real\n * documents clear this. See `ISaferFetchOptions.maxResponseBytes`.\n * @public\n */\nexport const DEFAULT_MAX_RESPONSE_BYTES: number = 5 * 1024 * 1024;\n\n/**\n * Redirect statuses this primitive recognizes as redirects. Other 3xx statuses (`300`, `304`,\n * …) do not direct the client at a new URL and are reported as ordinary non-2xx responses.\n * @public\n */\nexport const REDIRECT_STATUSES: ReadonlyArray<number> = [301, 302, 303, 307, 308];\n\n/**\n * Default cap on redirect hops followed under `'validate-each-hop'`.\n *\n * @remarks\n * Five is enough for the ordinary shortener-then-canonicalize-then-CDN chains real services\n * produce and small enough that a chain designed to burn budget is refused quickly. Every hop\n * costs a full guard evaluation — including a DNS resolution — against the same overall\n * deadline, so the cap bounds work, not just politeness.\n * @public\n */\nexport const DEFAULT_MAX_REDIRECTS: number = 5;\n\n/**\n * Header names dropped on every cross-origin redirect hop, whatever the caller configured.\n *\n * @remarks\n * Turning on manual redirects makes this primitive responsible for a rule the platform was\n * applying for free: browsers and `curl` both strip credential headers when a redirect leaves\n * the origin, and a hand-rolled loop that replays them hands `Authorization: Bearer …` to\n * whatever host the redirect names. Callers add their own names with\n * `ISaferFetchOptions.sensitiveHeaders`; these three are not removable.\n * @public\n */\nexport const ALWAYS_STRIPPED_HEADERS: ReadonlyArray<string> = [\n 'authorization',\n 'cookie',\n 'proxy-authorization'\n];\n\n/**\n * URL schemes this primitive will ever request.\n *\n * @remarks\n * Core rejects everything else — `file:`, `data:`, `blob:`, `ftp:`, `gopher:`, `ws:` — outright\n * and at every hop, because none of them is a legitimate network fetch and each is a standard\n * SSRF payload. Deciding between `http:` and `https:`, and which ports are acceptable, belongs\n * to the address guard, which is why core does not narrow this further.\n * @public\n */\nexport const SUPPORTED_SCHEMES: ReadonlyArray<string> = ['http:', 'https:'];\n\n/**\n * Default base delay for {@link SaferFetch.IRetryPolicy | retry} backoff, in milliseconds.\n * @public\n */\nexport const DEFAULT_RETRY_BASE_DELAY_MS: number = 250;\n\n/**\n * Default ceiling on a single {@link SaferFetch.IRetryPolicy | retry} delay, in milliseconds.\n *\n * @remarks\n * It bounds the computed backoff **and** a server-supplied `Retry-After`. That second role is\n * the security-relevant one: `Retry-After` is a header an attacker-controlled server chooses\n * freely, so an unclamped `Retry-After: 86400` is a denial of service on the caller.\n * @public\n */\nexport const DEFAULT_RETRY_MAX_DELAY_MS: number = 5_000;\n\n/**\n * HTTP statuses a {@link SaferFetch.IRetryPolicy | retry policy} will retry.\n *\n * @remarks\n * Every other status — including every other 4xx — is terminal. A `401`, a `403` and a `404`\n * mean the same thing on the second attempt as on the first, and retrying them turns a client\n * bug into load against a service that already said no.\n * @public\n */\nexport const RETRYABLE_HTTP_STATUSES: ReadonlyArray<number> = [408, 429, 500, 502, 503, 504];\n\n/**\n * Statuses whose `Retry-After` header is honored.\n *\n * @remarks\n * `429` and `503` are the two the header is specified for and the two where it carries real\n * scheduling information. Honoring it on a `500` would let any failing endpoint dictate the\n * caller's schedule for no benefit.\n * @public\n */\nexport const RETRY_AFTER_STATUSES: ReadonlyArray<number> = [429, 503];\n\n/**\n * Methods retried without an explicit opt-in.\n *\n * @remarks\n * A timeout does not tell you whether the server processed the request, so a retried `POST`\n * can double-charge. `retryNonIdempotent` opts out, per call, visibly.\n * @public\n */\nexport const IDEMPOTENT_METHODS: ReadonlyArray<string> = ['GET', 'HEAD'];\n"]}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Which deadline a {@link SaferFetch.FetchFailureReason | timeout failure} belongs to.
3
+ *
4
+ * - `'headers'`: the per-attempt headers deadline elapsed before the server sent
5
+ * response headers — the host is not answering.
6
+ * - `'body'`: the overall deadline elapsed while the response body was being read
7
+ * — the host answered and then trickled (the slowloris shape).
8
+ * - `'overall'`: the overall deadline elapsed before response headers arrived.
9
+ * @public
10
+ */
11
+ export type FetchTimeoutPhase = 'headers' | 'body' | 'overall';
12
+ /**
13
+ * Machine-readable reason a safer-fetch call failed, carried as the detail of the
14
+ * `DetailedResult` every entry point returns.
15
+ *
16
+ * @remarks
17
+ * **This value is an internal-network scanning oracle. Do not echo it, or any string
18
+ * derived from it, to an untrusted caller.** A `'blocked-by-guard'` detail names the
19
+ * URL, the hop, and the guard that rejected it; an attacker who can influence the
20
+ * request URL and observe the error learns whether an internal host exists. Log the
21
+ * detail; return a coarse code (the `kind` alone, or a generic message) to callers.
22
+ *
23
+ * Following the `AiAssist.JsonParseFailureReason` precedent in this package: a `kind`
24
+ * discriminant with per-kind payload fields, and `'unknown'` as an honest catch-all
25
+ * rather than a guess.
26
+ * @public
27
+ */
28
+ export type FetchFailureReason =
29
+ /** The supplied URL could not be parsed, or its scheme is not `http:` or `https:`. */
30
+ {
31
+ readonly kind: 'invalid-url';
32
+ readonly url: string;
33
+ readonly detail: string;
34
+ }
35
+ /**
36
+ * A guard refused. `hop` is 0-based; hop 0 is the caller's URL, and `guard` names which
37
+ * guard rejected — which is what makes "did the address check run, and was it the thing that
38
+ * said no?" answerable from the failure alone. A content-type rejection is reported as
39
+ * `'unsupported-content-type'` instead, because that case carries a more useful payload.
40
+ */
41
+ | {
42
+ readonly kind: 'blocked-by-guard';
43
+ readonly url: string;
44
+ readonly hop: number;
45
+ readonly guard: string;
46
+ readonly detail: string;
47
+ }
48
+ /**
49
+ * A redirect status was received that this call would not follow: the policy is `'reject'`,
50
+ * or the response carried no usable `Location`, or following it would revisit a URL already
51
+ * in the chain.
52
+ *
53
+ * @remarks
54
+ * The three are deliberately one kind. Splitting them would buy a caller almost nothing and
55
+ * would widen the scanning oracle this taxonomy already is — and the two follow-time cases
56
+ * are facts about the chain the redirecting server produced, not about the network behind
57
+ * this process. "The chain got too long" is a different question and stays
58
+ * `'too-many-redirects'`.
59
+ *
60
+ * `url` is always the URL that **issued** the rejected redirect — the hop this call actually
61
+ * requested and got a 3xx back from — never the `Location` target it pointed at. That holds
62
+ * for all three cases, including the revisit case, where the target is the URL already in the
63
+ * chain and naming it here would make the same field mean two different things. The target is
64
+ * named in the message instead. `status` is the redirect status that was received.
65
+ */
66
+ | {
67
+ readonly kind: 'redirect-rejected';
68
+ readonly url: string;
69
+ readonly status: number;
70
+ }
71
+ /**
72
+ * The platform returned an opaque redirect, whose `Location` is not readable. This is
73
+ * what a browser yields for `redirect: 'manual'`; the hop cannot be inspected at all.
74
+ */
75
+ | {
76
+ readonly kind: 'redirect-opaque';
77
+ }
78
+ /** The redirect hop budget was exhausted. */
79
+ | {
80
+ readonly kind: 'too-many-redirects';
81
+ readonly hops: number;
82
+ readonly limit: number;
83
+ }
84
+ /** One of the deadlines elapsed. Distinct from `'aborted'`, which is the caller's signal. */
85
+ | {
86
+ readonly kind: 'timeout';
87
+ readonly phase: FetchTimeoutPhase;
88
+ readonly elapsedMs: number;
89
+ readonly limitMs: number;
90
+ }
91
+ /** The caller's `AbortSignal` fired. Distinct from `'timeout'`, which is our deadline. */
92
+ | {
93
+ readonly kind: 'aborted';
94
+ }
95
+ /** The transport could not complete the request. */
96
+ | {
97
+ readonly kind: 'network';
98
+ readonly detail: string;
99
+ }
100
+ /**
101
+ * A non-2xx response. `bodyPreview` is **never populated in this release** — error bodies
102
+ * routinely echo request content, including credentials, so surfacing one has to be an
103
+ * explicit, length-capped opt-in rather than a default. The field is declared so that adding
104
+ * that opt-in later is additive.
105
+ */
106
+ | {
107
+ readonly kind: 'http-status';
108
+ readonly status: number;
109
+ readonly statusText: string;
110
+ readonly bodyPreview?: string;
111
+ }
112
+ /**
113
+ * The response exceeded the byte cap. `declared` is what `Content-Length` claimed, present
114
+ * only when the header was sent — and it counts *encoded* bytes where `bytesRead` counts
115
+ * *decoded* bytes, so a `declared` far below `bytesRead` is evidence of a compression bomb
116
+ * or a lying server rather than an arithmetic error.
117
+ */
118
+ | {
119
+ readonly kind: 'too-large';
120
+ readonly bytesRead: number;
121
+ readonly limit: number;
122
+ readonly declared?: number;
123
+ }
124
+ /** A response-headers guard rejected the response's content type. */
125
+ | {
126
+ readonly kind: 'unsupported-content-type';
127
+ readonly contentType?: string;
128
+ readonly accepted: ReadonlyArray<string>;
129
+ }
130
+ /** The response bytes could not be decoded to text with the indicated charset. */
131
+ | {
132
+ readonly kind: 'decode';
133
+ readonly detail: string;
134
+ }
135
+ /** The decoded text could not be parsed, or failed the caller's converter. */
136
+ | {
137
+ readonly kind: 'parse';
138
+ readonly detail: string;
139
+ }
140
+ /**
141
+ * Anything else — including invalid options and a guard or transport that violated its
142
+ * contract. Reports what it knows rather than guessing at a more specific kind.
143
+ */
144
+ | {
145
+ readonly kind: 'unknown';
146
+ readonly detail: string;
147
+ };
148
+ //# sourceMappingURL=failureReason.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failureReason.d.ts","sourceRoot":"","sources":["../../../src/packlets/safer-fetch/failureReason.ts"],"names":[],"mappings":"AAoBA;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAE/D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,kBAAkB;AAC5B,sFAAsF;AACpF;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACjF;;;;;GAKG;GACD;IACE,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AACH;;;;;;;;;;;;;;;;;GAiBG;GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACvF;;;GAGG;GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAA;CAAE;AACtC,6CAA6C;GAC3C;IAAE,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AACxF,6FAA6F;GAC3F;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AACH,0FAA0F;GACxF;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE;AAC9B,oDAAoD;GAClD;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACvD;;;;;GAKG;GACD;IACE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AACH;;;;;GAKG;GACD;IACE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AACH,qEAAqE;GACnE;IACE,QAAQ,CAAC,IAAI,EAAE,0BAA0B,CAAC;IAC1C,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC1C;AACH,kFAAkF;GAChF;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACtD,8EAA8E;GAC5E;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACrD;;;GAGG;GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC"}
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ // Copyright (c) 2026 Erik Fortune
3
+ //
4
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ // of this software and associated documentation files (the "Software"), to deal
6
+ // in the Software without restriction, including without limitation the rights
7
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ // copies of the Software, and to permit persons to whom the Software is
9
+ // furnished to do so, subject to the following conditions:
10
+ //
11
+ // The above copyright notice and this permission notice shall be included in all
12
+ // copies or substantial portions of the Software.
13
+ //
14
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ // SOFTWARE.
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ //# sourceMappingURL=failureReason.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failureReason.js","sourceRoot":"","sources":["../../../src/packlets/safer-fetch/failureReason.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","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 * Which deadline a {@link SaferFetch.FetchFailureReason | timeout failure} belongs to.\n *\n * - `'headers'`: the per-attempt headers deadline elapsed before the server sent\n * response headers — the host is not answering.\n * - `'body'`: the overall deadline elapsed while the response body was being read\n * — the host answered and then trickled (the slowloris shape).\n * - `'overall'`: the overall deadline elapsed before response headers arrived.\n * @public\n */\nexport type FetchTimeoutPhase = 'headers' | 'body' | 'overall';\n\n/**\n * Machine-readable reason a safer-fetch call failed, carried as the detail of the\n * `DetailedResult` every entry point returns.\n *\n * @remarks\n * **This value is an internal-network scanning oracle. Do not echo it, or any string\n * derived from it, to an untrusted caller.** A `'blocked-by-guard'` detail names the\n * URL, the hop, and the guard that rejected it; an attacker who can influence the\n * request URL and observe the error learns whether an internal host exists. Log the\n * detail; return a coarse code (the `kind` alone, or a generic message) to callers.\n *\n * Following the `AiAssist.JsonParseFailureReason` precedent in this package: a `kind`\n * discriminant with per-kind payload fields, and `'unknown'` as an honest catch-all\n * rather than a guess.\n * @public\n */\nexport type FetchFailureReason =\n /** The supplied URL could not be parsed, or its scheme is not `http:` or `https:`. */\n | { readonly kind: 'invalid-url'; readonly url: string; readonly detail: string }\n /**\n * A guard refused. `hop` is 0-based; hop 0 is the caller's URL, and `guard` names which\n * guard rejected — which is what makes \"did the address check run, and was it the thing that\n * said no?\" answerable from the failure alone. A content-type rejection is reported as\n * `'unsupported-content-type'` instead, because that case carries a more useful payload.\n */\n | {\n readonly kind: 'blocked-by-guard';\n readonly url: string;\n readonly hop: number;\n readonly guard: string;\n readonly detail: string;\n }\n /**\n * A redirect status was received that this call would not follow: the policy is `'reject'`,\n * or the response carried no usable `Location`, or following it would revisit a URL already\n * in the chain.\n *\n * @remarks\n * The three are deliberately one kind. Splitting them would buy a caller almost nothing and\n * would widen the scanning oracle this taxonomy already is — and the two follow-time cases\n * are facts about the chain the redirecting server produced, not about the network behind\n * this process. \"The chain got too long\" is a different question and stays\n * `'too-many-redirects'`.\n *\n * `url` is always the URL that **issued** the rejected redirect — the hop this call actually\n * requested and got a 3xx back from — never the `Location` target it pointed at. That holds\n * for all three cases, including the revisit case, where the target is the URL already in the\n * chain and naming it here would make the same field mean two different things. The target is\n * named in the message instead. `status` is the redirect status that was received.\n */\n | { readonly kind: 'redirect-rejected'; readonly url: string; readonly status: number }\n /**\n * The platform returned an opaque redirect, whose `Location` is not readable. This is\n * what a browser yields for `redirect: 'manual'`; the hop cannot be inspected at all.\n */\n | { readonly kind: 'redirect-opaque' }\n /** The redirect hop budget was exhausted. */\n | { readonly kind: 'too-many-redirects'; readonly hops: number; readonly limit: number }\n /** One of the deadlines elapsed. Distinct from `'aborted'`, which is the caller's signal. */\n | {\n readonly kind: 'timeout';\n readonly phase: FetchTimeoutPhase;\n readonly elapsedMs: number;\n readonly limitMs: number;\n }\n /** The caller's `AbortSignal` fired. Distinct from `'timeout'`, which is our deadline. */\n | { readonly kind: 'aborted' }\n /** The transport could not complete the request. */\n | { readonly kind: 'network'; readonly detail: string }\n /**\n * A non-2xx response. `bodyPreview` is **never populated in this release** — error bodies\n * routinely echo request content, including credentials, so surfacing one has to be an\n * explicit, length-capped opt-in rather than a default. The field is declared so that adding\n * that opt-in later is additive.\n */\n | {\n readonly kind: 'http-status';\n readonly status: number;\n readonly statusText: string;\n readonly bodyPreview?: string;\n }\n /**\n * The response exceeded the byte cap. `declared` is what `Content-Length` claimed, present\n * only when the header was sent — and it counts *encoded* bytes where `bytesRead` counts\n * *decoded* bytes, so a `declared` far below `bytesRead` is evidence of a compression bomb\n * or a lying server rather than an arithmetic error.\n */\n | {\n readonly kind: 'too-large';\n readonly bytesRead: number;\n readonly limit: number;\n readonly declared?: number;\n }\n /** A response-headers guard rejected the response's content type. */\n | {\n readonly kind: 'unsupported-content-type';\n readonly contentType?: string;\n readonly accepted: ReadonlyArray<string>;\n }\n /** The response bytes could not be decoded to text with the indicated charset. */\n | { readonly kind: 'decode'; readonly detail: string }\n /** The decoded text could not be parsed, or failed the caller's converter. */\n | { readonly kind: 'parse'; readonly detail: string }\n /**\n * Anything else — including invalid options and a guard or transport that violated its\n * contract. Reports what it knows rather than guessing at a more specific kind.\n */\n | { readonly kind: 'unknown'; readonly detail: string };\n"]}
@@ -0,0 +1,62 @@
1
+ import { Result } from '@fgv/ts-utils';
2
+ import type { IAddressGuard, IResolvedGuards, IResponseHeadersGuard, ISaferFetchOptions } from './model';
3
+ /**
4
+ * An address guard that permits every address.
5
+ *
6
+ * @remarks
7
+ * **This is the absence of the SSRF guarantee, given a name.** It performs no address
8
+ * classification, no DNS resolution, and no scheme or port narrowing beyond the core's
9
+ * refusal of non-`http(s)` schemes. A call site using it is reachable at any address the
10
+ * process can route to, including cloud metadata endpoints, loopback admin ports, and
11
+ * RFC-1918 hosts.
12
+ *
13
+ * It ships anyway, for two reasons. It is the honest and only possible choice in a browser,
14
+ * where neither DNS resolution nor redirect interposition exists. And omitting it would not
15
+ * make anyone safer — it would make consumers hand-roll something worse. It is deliberately
16
+ * named to be uncomfortable in review and to grep as a distinct posture.
17
+ *
18
+ * This is the **guard-layer** factory: it returns an {@link SaferFetch.IAddressGuard}, which is
19
+ * what an entry point's `addressGuard` option takes. A pure address *policy* — the synchronous,
20
+ * address-list-in classifier a resolving guard delegates to — is a different layer and needs a
21
+ * distinct name.
22
+ * @public
23
+ */
24
+ export declare function allowAnyAddress(): IAddressGuard;
25
+ /**
26
+ * A response-headers guard that accepts only the listed media types.
27
+ *
28
+ * @remarks
29
+ * Rejecting on `Content-Type` is strictly cheaper than capping mid-read — a header comparison
30
+ * instead of a partial body transfer — so a consumer ingesting URLs wants it on every call. It
31
+ * is also what keeps an HTML error page served with a `200` from being parsed as JSON twenty
32
+ * frames away from where it went wrong.
33
+ *
34
+ * Entries are media types, optionally with a wildcard subtype (`text/*`); a wildcard type
35
+ * requires a wildcard subtype. Matching is case-insensitive and ignores parameters, so
36
+ * `text/html` accepts `text/html; charset=utf-8`. A response with **no** `Content-Type` is
37
+ * rejected: an untyped response has not satisfied a content-type allowlist.
38
+ *
39
+ * Construction is fallible because a malformed entry in a security-adjacent allowlist must be
40
+ * reported to its author rather than silently compiled into a pattern that never matches.
41
+ *
42
+ * @param types - Accepted media types. Must be non-empty.
43
+ * @public
44
+ */
45
+ export declare function allowContentTypes(types: ReadonlyArray<string>): Result<IResponseHeadersGuard>;
46
+ /**
47
+ * Resolves the guards a call will use, applying defaults once at the boundary so that no
48
+ * downstream code path branches on a guard's absence.
49
+ *
50
+ * @remarks
51
+ * Every optional guard resolves with `??`, uniformly. That uniformity is the point: a
52
+ * `!== undefined` test in one slot where its siblings use `??` lets a `null` — from a
53
+ * JavaScript caller, or through an `unknown` escape hatch — pass straight through and install
54
+ * itself as a guard, which is a real defect that has shipped in this repo before. A `null`
55
+ * guard here is treated as *absent*, never as *installed*.
56
+ *
57
+ * `addressGuard` has no default, so a `null` or missing value is a hard failure rather than a
58
+ * silent passthrough.
59
+ * @internal
60
+ */
61
+ export declare function resolveGuards(options: ISaferFetchOptions): Result<IResolvedGuards>;
62
+ //# sourceMappingURL=guards.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../../../src/packlets/safer-fetch/guards.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAoB,MAAM,EAAW,MAAM,eAAe,CAAC;AAGlE,OAAO,KAAK,EACV,aAAa,EAIb,eAAe,EAEf,qBAAqB,EACrB,kBAAkB,EAGnB,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,IAAI,aAAa,CAa/C;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,qBAAqB,CAAC,CA6B7F;AAiBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAAC,eAAe,CAAC,CAclF"}
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ // Copyright (c) 2026 Erik Fortune
3
+ //
4
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ // of this software and associated documentation files (the "Software"), to deal
6
+ // in the Software without restriction, including without limitation the rights
7
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ // copies of the Software, and to permit persons to whom the Software is
9
+ // furnished to do so, subject to the following conditions:
10
+ //
11
+ // The above copyright notice and this permission notice shall be included in all
12
+ // copies or substantial portions of the Software.
13
+ //
14
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ // SOFTWARE.
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.allowAnyAddress = allowAnyAddress;
23
+ exports.allowContentTypes = allowContentTypes;
24
+ exports.resolveGuards = resolveGuards;
25
+ const ts_utils_1 = require("@fgv/ts-utils");
26
+ const contentType_1 = require("./contentType");
27
+ /**
28
+ * An address guard that permits every address.
29
+ *
30
+ * @remarks
31
+ * **This is the absence of the SSRF guarantee, given a name.** It performs no address
32
+ * classification, no DNS resolution, and no scheme or port narrowing beyond the core's
33
+ * refusal of non-`http(s)` schemes. A call site using it is reachable at any address the
34
+ * process can route to, including cloud metadata endpoints, loopback admin ports, and
35
+ * RFC-1918 hosts.
36
+ *
37
+ * It ships anyway, for two reasons. It is the honest and only possible choice in a browser,
38
+ * where neither DNS resolution nor redirect interposition exists. And omitting it would not
39
+ * make anyone safer — it would make consumers hand-roll something worse. It is deliberately
40
+ * named to be uncomfortable in review and to grep as a distinct posture.
41
+ *
42
+ * This is the **guard-layer** factory: it returns an {@link SaferFetch.IAddressGuard}, which is
43
+ * what an entry point's `addressGuard` option takes. A pure address *policy* — the synchronous,
44
+ * address-list-in classifier a resolving guard delegates to — is a different layer and needs a
45
+ * distinct name.
46
+ * @public
47
+ */
48
+ function allowAnyAddress() {
49
+ return {
50
+ name: 'allowAnyAddress',
51
+ check: async (chain) => {
52
+ var _a;
53
+ const hop = (_a = chain[chain.length - 1]) !== null && _a !== void 0 ? _a : undefined;
54
+ if (hop === undefined) {
55
+ return (0, ts_utils_1.fail)('allowAnyAddress: hop chain is empty.');
56
+ }
57
+ // pinnedAddress is deliberately left undefined: this guard validates nothing, so it has
58
+ // no address to pin, and a transport must never be told otherwise.
59
+ return (0, ts_utils_1.succeed)({ url: hop.url });
60
+ }
61
+ };
62
+ }
63
+ /**
64
+ * A response-headers guard that accepts only the listed media types.
65
+ *
66
+ * @remarks
67
+ * Rejecting on `Content-Type` is strictly cheaper than capping mid-read — a header comparison
68
+ * instead of a partial body transfer — so a consumer ingesting URLs wants it on every call. It
69
+ * is also what keeps an HTML error page served with a `200` from being parsed as JSON twenty
70
+ * frames away from where it went wrong.
71
+ *
72
+ * Entries are media types, optionally with a wildcard subtype (`text/*`); a wildcard type
73
+ * requires a wildcard subtype. Matching is case-insensitive and ignores parameters, so
74
+ * `text/html` accepts `text/html; charset=utf-8`. A response with **no** `Content-Type` is
75
+ * rejected: an untyped response has not satisfied a content-type allowlist.
76
+ *
77
+ * Construction is fallible because a malformed entry in a security-adjacent allowlist must be
78
+ * reported to its author rather than silently compiled into a pattern that never matches.
79
+ *
80
+ * @param types - Accepted media types. Must be non-empty.
81
+ * @public
82
+ */
83
+ function allowContentTypes(types) {
84
+ if (types.length === 0) {
85
+ return (0, ts_utils_1.fail)('allowContentTypes: at least one media type is required.');
86
+ }
87
+ return (0, ts_utils_1.mapResults)(types.map((t) => (0, contentType_1.parseMediaTypePattern)(t)))
88
+ .withErrorFormat((message) => `allowContentTypes: ${message}`)
89
+ .onSuccess((patterns) => {
90
+ const accepted = patterns.map((p) => `${p.type}/${p.subtype}`);
91
+ return (0, ts_utils_1.succeed)({
92
+ name: 'allowContentTypes',
93
+ acceptedContentTypes: accepted,
94
+ check: async (head) => {
95
+ var _a;
96
+ const contentType = (_a = head.contentType) !== null && _a !== void 0 ? _a : undefined;
97
+ if (contentType === undefined) {
98
+ return (0, ts_utils_1.fail)(`response has no content-type; expected one of [${accepted.join(', ')}].`);
99
+ }
100
+ return (0, contentType_1.parseMediaType)(contentType)
101
+ .withErrorFormat((message) => `content-type ${message}`)
102
+ .onSuccess((actual) => {
103
+ if (patterns.some((p) => (0, contentType_1.mediaTypeMatches)(actual, p))) {
104
+ return (0, ts_utils_1.succeed)(true);
105
+ }
106
+ return (0, ts_utils_1.fail)(`content-type "${contentType}" is not accepted; expected one of [${accepted.join(', ')}].`);
107
+ });
108
+ }
109
+ });
110
+ });
111
+ }
112
+ const passthroughRequestGuard = {
113
+ name: 'passthrough',
114
+ check: async (request) => (0, ts_utils_1.succeed)(request)
115
+ };
116
+ const passthroughResponseHeadersGuard = {
117
+ name: 'passthrough',
118
+ check: async () => (0, ts_utils_1.succeed)(true)
119
+ };
120
+ const passthroughResponseBodyGuard = {
121
+ name: 'passthrough',
122
+ check: async () => (0, ts_utils_1.succeed)(true)
123
+ };
124
+ /**
125
+ * Resolves the guards a call will use, applying defaults once at the boundary so that no
126
+ * downstream code path branches on a guard's absence.
127
+ *
128
+ * @remarks
129
+ * Every optional guard resolves with `??`, uniformly. That uniformity is the point: a
130
+ * `!== undefined` test in one slot where its siblings use `??` lets a `null` — from a
131
+ * JavaScript caller, or through an `unknown` escape hatch — pass straight through and install
132
+ * itself as a guard, which is a real defect that has shipped in this repo before. A `null`
133
+ * guard here is treated as *absent*, never as *installed*.
134
+ *
135
+ * `addressGuard` has no default, so a `null` or missing value is a hard failure rather than a
136
+ * silent passthrough.
137
+ * @internal
138
+ */
139
+ function resolveGuards(options) {
140
+ var _a, _b, _c, _d;
141
+ const address = (_a = options.addressGuard) !== null && _a !== void 0 ? _a : undefined;
142
+ if (address === undefined) {
143
+ return (0, ts_utils_1.fail)('addressGuard is required and has no default. Supply a named factory — ' +
144
+ 'allowAnyAddress() is the explicit opt-out.');
145
+ }
146
+ return (0, ts_utils_1.succeed)({
147
+ address,
148
+ request: (_b = options.requestGuard) !== null && _b !== void 0 ? _b : passthroughRequestGuard,
149
+ responseHeaders: (_c = options.responseHeadersGuard) !== null && _c !== void 0 ? _c : passthroughResponseHeadersGuard,
150
+ responseBody: (_d = options.responseBodyGuard) !== null && _d !== void 0 ? _d : passthroughResponseBodyGuard
151
+ });
152
+ }
153
+ //# sourceMappingURL=guards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.js","sourceRoot":"","sources":["../../../src/packlets/safer-fetch/guards.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;;AAuCZ,0CAaC;AAsBD,8CA6BC;AAgCD,sCAcC;AAnJD,4CAAkE;AAElE,+CAAoG;AAcpG;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAgB,eAAe;IAC7B,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,KAAK,EAAE,KAAK,EAAE,KAAiC,EAAkC,EAAE;;YACjF,MAAM,GAAG,GAAG,MAAA,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,mCAAI,SAAS,CAAC;YACjD,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,OAAO,IAAA,eAAI,EAAC,sCAAsC,CAAC,CAAC;YACtD,CAAC;YACD,wFAAwF;YACxF,mEAAmE;YACnE,OAAO,IAAA,kBAAO,EAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;QACnC,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,SAAgB,iBAAiB,CAAC,KAA4B;IAC5D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,IAAA,eAAI,EAAC,yDAAyD,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,IAAA,qBAAU,EAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,mCAAqB,EAAC,CAAC,CAAC,CAAC,CAAC;SAC1D,eAAe,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,sBAAsB,OAAO,EAAE,CAAC;SAC7D,SAAS,CAAC,CAAC,QAAsB,EAAE,EAAE;QACpC,MAAM,QAAQ,GAA0B,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACtF,OAAO,IAAA,kBAAO,EAAC;YACb,IAAI,EAAE,mBAAmB;YACzB,oBAAoB,EAAE,QAAQ;YAC9B,KAAK,EAAE,KAAK,EAAE,IAA6B,EAAyB,EAAE;;gBACpE,MAAM,WAAW,GAAG,MAAA,IAAI,CAAC,WAAW,mCAAI,SAAS,CAAC;gBAClD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;oBAC9B,OAAO,IAAA,eAAI,EAAC,kDAAkD,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACzF,CAAC;gBACD,OAAO,IAAA,4BAAc,EAAC,WAAW,CAAC;qBAC/B,eAAe,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,gBAAgB,OAAO,EAAE,CAAC;qBACvD,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE;oBACpB,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,8BAAgB,EAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;wBACtD,OAAO,IAAA,kBAAO,EAAC,IAAa,CAAC,CAAC;oBAChC,CAAC;oBACD,OAAO,IAAA,eAAI,EACT,iBAAiB,WAAW,uCAAuC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAC3F,CAAC;gBACJ,CAAC,CAAC,CAAC;YACP,CAAC;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,uBAAuB,GAAkB;IAC7C,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,KAAK,EAAE,OAA2B,EAAuC,EAAE,CAAC,IAAA,kBAAO,EAAC,OAAO,CAAC;CACpG,CAAC;AAEF,MAAM,+BAA+B,GAA0B;IAC7D,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,KAAK,IAA2B,EAAE,CAAC,IAAA,kBAAO,EAAC,IAAa,CAAC;CACjE,CAAC;AAEF,MAAM,4BAA4B,GAAuB;IACvD,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,KAAK,IAA2B,EAAE,CAAC,IAAA,kBAAO,EAAC,IAAa,CAAC;CACjE,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,SAAgB,aAAa,CAAC,OAA2B;;IACvD,MAAM,OAAO,GAAG,MAAA,OAAO,CAAC,YAAY,mCAAI,SAAS,CAAC;IAClD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,IAAA,eAAI,EACT,wEAAwE;YACtE,4CAA4C,CAC/C,CAAC;IACJ,CAAC;IACD,OAAO,IAAA,kBAAO,EAAC;QACb,OAAO;QACP,OAAO,EAAE,MAAA,OAAO,CAAC,YAAY,mCAAI,uBAAuB;QACxD,eAAe,EAAE,MAAA,OAAO,CAAC,oBAAoB,mCAAI,+BAA+B;QAChF,YAAY,EAAE,MAAA,OAAO,CAAC,iBAAiB,mCAAI,4BAA4B;KACxE,CAAC,CAAC;AACL,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\nimport { fail, mapResults, Result, succeed } from '@fgv/ts-utils';\n\nimport { IMediaType, mediaTypeMatches, parseMediaType, parseMediaTypePattern } from './contentType';\nimport type {\n IAddressGuard,\n IGuardVerdict,\n IRequestGuard,\n IRequestHop,\n IResolvedGuards,\n IResponseBodyGuard,\n IResponseHeadersGuard,\n ISaferFetchOptions,\n ISaferFetchRequest,\n ISaferFetchResponseHead\n} from './model';\n\n/**\n * An address guard that permits every address.\n *\n * @remarks\n * **This is the absence of the SSRF guarantee, given a name.** It performs no address\n * classification, no DNS resolution, and no scheme or port narrowing beyond the core's\n * refusal of non-`http(s)` schemes. A call site using it is reachable at any address the\n * process can route to, including cloud metadata endpoints, loopback admin ports, and\n * RFC-1918 hosts.\n *\n * It ships anyway, for two reasons. It is the honest and only possible choice in a browser,\n * where neither DNS resolution nor redirect interposition exists. And omitting it would not\n * make anyone safer — it would make consumers hand-roll something worse. It is deliberately\n * named to be uncomfortable in review and to grep as a distinct posture.\n *\n * This is the **guard-layer** factory: it returns an {@link SaferFetch.IAddressGuard}, which is\n * what an entry point's `addressGuard` option takes. A pure address *policy* — the synchronous,\n * address-list-in classifier a resolving guard delegates to — is a different layer and needs a\n * distinct name.\n * @public\n */\nexport function allowAnyAddress(): IAddressGuard {\n return {\n name: 'allowAnyAddress',\n check: async (chain: ReadonlyArray<IRequestHop>): Promise<Result<IGuardVerdict>> => {\n const hop = chain[chain.length - 1] ?? undefined;\n if (hop === undefined) {\n return fail('allowAnyAddress: hop chain is empty.');\n }\n // pinnedAddress is deliberately left undefined: this guard validates nothing, so it has\n // no address to pin, and a transport must never be told otherwise.\n return succeed({ url: hop.url });\n }\n };\n}\n\n/**\n * A response-headers guard that accepts only the listed media types.\n *\n * @remarks\n * Rejecting on `Content-Type` is strictly cheaper than capping mid-read — a header comparison\n * instead of a partial body transfer — so a consumer ingesting URLs wants it on every call. It\n * is also what keeps an HTML error page served with a `200` from being parsed as JSON twenty\n * frames away from where it went wrong.\n *\n * Entries are media types, optionally with a wildcard subtype (`text/*`); a wildcard type\n * requires a wildcard subtype. Matching is case-insensitive and ignores parameters, so\n * `text/html` accepts `text/html; charset=utf-8`. A response with **no** `Content-Type` is\n * rejected: an untyped response has not satisfied a content-type allowlist.\n *\n * Construction is fallible because a malformed entry in a security-adjacent allowlist must be\n * reported to its author rather than silently compiled into a pattern that never matches.\n *\n * @param types - Accepted media types. Must be non-empty.\n * @public\n */\nexport function allowContentTypes(types: ReadonlyArray<string>): Result<IResponseHeadersGuard> {\n if (types.length === 0) {\n return fail('allowContentTypes: at least one media type is required.');\n }\n return mapResults(types.map((t) => parseMediaTypePattern(t)))\n .withErrorFormat((message) => `allowContentTypes: ${message}`)\n .onSuccess((patterns: IMediaType[]) => {\n const accepted: ReadonlyArray<string> = patterns.map((p) => `${p.type}/${p.subtype}`);\n return succeed({\n name: 'allowContentTypes',\n acceptedContentTypes: accepted,\n check: async (head: ISaferFetchResponseHead): Promise<Result<true>> => {\n const contentType = head.contentType ?? undefined;\n if (contentType === undefined) {\n return fail(`response has no content-type; expected one of [${accepted.join(', ')}].`);\n }\n return parseMediaType(contentType)\n .withErrorFormat((message) => `content-type ${message}`)\n .onSuccess((actual) => {\n if (patterns.some((p) => mediaTypeMatches(actual, p))) {\n return succeed(true as const);\n }\n return fail(\n `content-type \"${contentType}\" is not accepted; expected one of [${accepted.join(', ')}].`\n );\n });\n }\n });\n });\n}\n\nconst passthroughRequestGuard: IRequestGuard = {\n name: 'passthrough',\n check: async (request: ISaferFetchRequest): Promise<Result<ISaferFetchRequest>> => succeed(request)\n};\n\nconst passthroughResponseHeadersGuard: IResponseHeadersGuard = {\n name: 'passthrough',\n check: async (): Promise<Result<true>> => succeed(true as const)\n};\n\nconst passthroughResponseBodyGuard: IResponseBodyGuard = {\n name: 'passthrough',\n check: async (): Promise<Result<true>> => succeed(true as const)\n};\n\n/**\n * Resolves the guards a call will use, applying defaults once at the boundary so that no\n * downstream code path branches on a guard's absence.\n *\n * @remarks\n * Every optional guard resolves with `??`, uniformly. That uniformity is the point: a\n * `!== undefined` test in one slot where its siblings use `??` lets a `null` — from a\n * JavaScript caller, or through an `unknown` escape hatch — pass straight through and install\n * itself as a guard, which is a real defect that has shipped in this repo before. A `null`\n * guard here is treated as *absent*, never as *installed*.\n *\n * `addressGuard` has no default, so a `null` or missing value is a hard failure rather than a\n * silent passthrough.\n * @internal\n */\nexport function resolveGuards(options: ISaferFetchOptions): Result<IResolvedGuards> {\n const address = options.addressGuard ?? undefined;\n if (address === undefined) {\n return fail(\n 'addressGuard is required and has no default. Supply a named factory — ' +\n 'allowAnyAddress() is the explicit opt-out.'\n );\n }\n return succeed({\n address,\n request: options.requestGuard ?? passthroughRequestGuard,\n responseHeaders: options.responseHeadersGuard ?? passthroughResponseHeadersGuard,\n responseBody: options.responseBodyGuard ?? passthroughResponseBodyGuard\n });\n}\n"]}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * An HTTP fetch primitive with an explicit threat model (browser version).
3
+ *
4
+ * This barrel deliberately omits `blockPrivateNetworks` and the resolver seam beneath it: that
5
+ * module imports `node:dns/promises`, and exporting it here would pull a Node builtin into a
6
+ * browser bundle.
7
+ *
8
+ * The address-classification layer — `classifyAddress`, and the pure synchronous policies
9
+ * `allowAnyAddressPolicy` / `blockPrivateNetworksPolicy` — **is** exported here: it is pure
10
+ * arithmetic over parsed octets, it works identically in a browser, and it is useful for a
11
+ * URL-zero check. It is not a substitute for the guard, and cannot be: it classifies an address
12
+ * a caller already holds, while what the browser lacks is any way to learn the address a
13
+ * hostname resolves to.
14
+ *
15
+ * Note: the resolved-address (private-IP) guard and per-hop redirect revalidation are NOT
16
+ * available in a browser, and not for want of implementation. There is no browser API that
17
+ * returns a hostname's A/AAAA records, nothing in `fetch` or `Response` exposes the peer
18
+ * address, and `redirect: 'manual'` yields an opaque response whose `Location` is not
19
+ * readable — a `'validate-each-hop'` call there fails as `'redirect-opaque'` rather than
20
+ * quietly following anything. `allowAnyAddress()` is the honest choice, and its name says so.
21
+ *
22
+ * @packageDocumentation
23
+ */
24
+ export { ALWAYS_STRIPPED_HEADERS, DEFAULT_HEADERS_TIMEOUT_MS, DEFAULT_MAX_REDIRECTS, DEFAULT_MAX_RESPONSE_BYTES, DEFAULT_RETRY_BASE_DELAY_MS, DEFAULT_RETRY_MAX_DELAY_MS, DEFAULT_TIMEOUT_MS, IDEMPOTENT_METHODS, REDIRECT_STATUSES, RETRY_AFTER_STATUSES, RETRYABLE_HTTP_STATUSES, SUPPORTED_SCHEMES } from './defaults';
25
+ export type { FetchFailureReason, FetchTimeoutPhase } from './failureReason';
26
+ export type { IRetryPolicy } from './retry';
27
+ export type { IAddressGuard, IFetchTransport, IFetchTransportHints, IGuardVerdict, IRequestGuard, IRequestHop, IResolvedGuards, IResponseBodyGuard, IResponseHeadersGuard, ISaferFetchOptions, ISaferFetchRequest, ISaferFetchResponse, ISaferFetchResponseHead, SaferFetchMethod, SaferFetchRedirectPolicy } from './model';
28
+ export { allowAnyAddress, allowContentTypes } from './guards';
29
+ export { platformFetchTransport } from './transport';
30
+ export { saferFetchBytes, saferFetchJson, saferFetchText, type ISaferFetchJsonOptions } from './saferFetch';
31
+ export { allowAnyAddressPolicy, blockPrivateNetworksPolicy, type IAddressCheckVerdict, type IAddressPolicy, type IBlockPrivateNetworksOptions } from './addressPolicy';
32
+ export { classifyAddress, type AddressClassification, type AddressFamily, type IClassifiedAddress, type IEmbeddedIpv4, type Ipv4EmbeddingKind } from './addressClassification';
33
+ //# sourceMappingURL=index.browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.browser.d.ts","sourceRoot":"","sources":["../../../src/packlets/safer-fetch/index.browser.ts"],"names":[],"mappings":"AAoBA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,qBAAqB,EACrB,0BAA0B,EAC1B,2BAA2B,EAC3B,0BAA0B,EAC1B,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,uBAAuB,EACvB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC7E,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,YAAY,EACV,aAAa,EACb,eAAe,EACf,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,KAAK,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAW5G,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,4BAA4B,EAClC,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,eAAe,EACf,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACvB,MAAM,yBAAyB,CAAC"}