@fgv/ts-extras 5.1.0-3 → 5.1.0-30

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 (334) hide show
  1. package/dist/index.browser.js +4 -2
  2. package/dist/index.browser.js.map +1 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/packlets/ai-assist/apiClient.js +958 -131
  5. package/dist/packlets/ai-assist/apiClient.js.map +1 -0
  6. package/dist/packlets/ai-assist/chatRequestBuilders.js +186 -0
  7. package/dist/packlets/ai-assist/chatRequestBuilders.js.map +1 -0
  8. package/dist/packlets/ai-assist/converters.js +2 -1
  9. package/dist/packlets/ai-assist/converters.js.map +1 -0
  10. package/dist/packlets/ai-assist/endpoint.js +78 -0
  11. package/dist/packlets/ai-assist/endpoint.js.map +1 -0
  12. package/dist/packlets/ai-assist/imageOptionsResolver.js +212 -0
  13. package/dist/packlets/ai-assist/imageOptionsResolver.js.map +1 -0
  14. package/dist/packlets/ai-assist/index.js +7 -3
  15. package/dist/packlets/ai-assist/index.js.map +1 -0
  16. package/dist/packlets/ai-assist/jsonCompletion.js +95 -0
  17. package/dist/packlets/ai-assist/jsonCompletion.js.map +1 -0
  18. package/dist/packlets/ai-assist/jsonResponse.js +149 -0
  19. package/dist/packlets/ai-assist/jsonResponse.js.map +1 -0
  20. package/dist/packlets/ai-assist/model.js +21 -4
  21. package/dist/packlets/ai-assist/model.js.map +1 -0
  22. package/dist/packlets/ai-assist/registry.js +235 -10
  23. package/dist/packlets/ai-assist/registry.js.map +1 -0
  24. package/dist/packlets/ai-assist/sseParser.js +123 -0
  25. package/dist/packlets/ai-assist/sseParser.js.map +1 -0
  26. package/dist/packlets/ai-assist/streamingAdapters/anthropic.js +197 -0
  27. package/dist/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -0
  28. package/dist/packlets/ai-assist/streamingAdapters/common.js +79 -0
  29. package/dist/packlets/ai-assist/streamingAdapters/common.js.map +1 -0
  30. package/dist/packlets/ai-assist/streamingAdapters/gemini.js +172 -0
  31. package/dist/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -0
  32. package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js +165 -0
  33. package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -0
  34. package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js +179 -0
  35. package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -0
  36. package/dist/packlets/ai-assist/streamingAdapters/proxy.js +163 -0
  37. package/dist/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -0
  38. package/dist/packlets/ai-assist/streamingClient.js +116 -0
  39. package/dist/packlets/ai-assist/streamingClient.js.map +1 -0
  40. package/dist/packlets/ai-assist/thinkingOptionsResolver.js +265 -0
  41. package/dist/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -0
  42. package/dist/packlets/ai-assist/toolFormats.js.map +1 -0
  43. package/dist/packlets/conversion/converters.js +35 -1
  44. package/dist/packlets/conversion/converters.js.map +1 -0
  45. package/dist/packlets/conversion/index.js.map +1 -0
  46. package/dist/packlets/crypto-utils/constants.js.map +1 -0
  47. package/dist/packlets/crypto-utils/converters.js +24 -4
  48. package/dist/packlets/crypto-utils/converters.js.map +1 -0
  49. package/dist/packlets/crypto-utils/directEncryptionProvider.js.map +1 -0
  50. package/dist/packlets/crypto-utils/encryptedFile.js.map +1 -0
  51. package/dist/packlets/crypto-utils/hpkeProvider.js +333 -0
  52. package/dist/packlets/crypto-utils/hpkeProvider.js.map +1 -0
  53. package/dist/packlets/crypto-utils/index.browser.js +7 -0
  54. package/dist/packlets/crypto-utils/index.browser.js.map +1 -0
  55. package/dist/packlets/crypto-utils/index.js +6 -0
  56. package/dist/packlets/crypto-utils/index.js.map +1 -0
  57. package/dist/packlets/crypto-utils/keyPairAlgorithmParams.js +71 -0
  58. package/dist/packlets/crypto-utils/keyPairAlgorithmParams.js.map +1 -0
  59. package/dist/packlets/crypto-utils/keystore/converters.js +103 -11
  60. package/dist/packlets/crypto-utils/keystore/converters.js.map +1 -0
  61. package/dist/packlets/crypto-utils/keystore/index.js +1 -0
  62. package/dist/packlets/crypto-utils/keystore/index.js.map +1 -0
  63. package/dist/packlets/crypto-utils/keystore/keyStore.js +618 -118
  64. package/dist/packlets/crypto-utils/keystore/keyStore.js.map +1 -0
  65. package/dist/packlets/crypto-utils/keystore/model.js +22 -1
  66. package/dist/packlets/crypto-utils/keystore/model.js.map +1 -0
  67. package/dist/packlets/crypto-utils/keystore/privateKeyStorage.js +21 -0
  68. package/dist/packlets/crypto-utils/keystore/privateKeyStorage.js.map +1 -0
  69. package/dist/packlets/crypto-utils/model.js +32 -0
  70. package/dist/packlets/crypto-utils/model.js.map +1 -0
  71. package/dist/packlets/crypto-utils/nodeCryptoProvider.js +270 -1
  72. package/dist/packlets/crypto-utils/nodeCryptoProvider.js.map +1 -0
  73. package/dist/packlets/crypto-utils/spkiHelpers.js +130 -0
  74. package/dist/packlets/crypto-utils/spkiHelpers.js.map +1 -0
  75. package/dist/packlets/csv/csvFileHelpers.js +0 -14
  76. package/dist/packlets/csv/csvFileHelpers.js.map +1 -0
  77. package/dist/packlets/csv/csvHelpers.js +14 -0
  78. package/dist/packlets/csv/csvHelpers.js.map +1 -0
  79. package/dist/packlets/csv/index.browser.js +1 -3
  80. package/dist/packlets/csv/index.browser.js.map +1 -0
  81. package/dist/packlets/csv/index.js.map +1 -0
  82. package/dist/packlets/experimental/extendedArray.js.map +1 -0
  83. package/dist/packlets/experimental/formatter.js.map +1 -0
  84. package/dist/packlets/experimental/index.js.map +1 -0
  85. package/dist/packlets/experimental/rangeOf.js.map +1 -0
  86. package/dist/packlets/hash/index.browser.js.map +1 -0
  87. package/dist/packlets/hash/index.js.map +1 -0
  88. package/dist/packlets/hash/index.node.js.map +1 -0
  89. package/dist/packlets/hash/md5Normalizer.browser.js.map +1 -0
  90. package/dist/packlets/hash/md5Normalizer.js.map +1 -0
  91. package/dist/packlets/mustache/index.js.map +1 -0
  92. package/dist/packlets/mustache/interfaces.js.map +1 -0
  93. package/dist/packlets/mustache/mustacheTemplate.js +42 -4
  94. package/dist/packlets/mustache/mustacheTemplate.js.map +1 -0
  95. package/dist/packlets/record-jar/index.browser.js +1 -3
  96. package/dist/packlets/record-jar/index.browser.js.map +1 -0
  97. package/dist/packlets/record-jar/index.js.map +1 -0
  98. package/dist/packlets/record-jar/recordJarFileHelpers.js +0 -18
  99. package/dist/packlets/record-jar/recordJarFileHelpers.js.map +1 -0
  100. package/dist/packlets/record-jar/recordJarHelpers.js +18 -0
  101. package/dist/packlets/record-jar/recordJarHelpers.js.map +1 -0
  102. package/dist/packlets/yaml/converters.js.map +1 -0
  103. package/dist/packlets/yaml/index.js +1 -0
  104. package/dist/packlets/yaml/index.js.map +1 -0
  105. package/dist/packlets/yaml/serializers.js +48 -0
  106. package/dist/packlets/yaml/serializers.js.map +1 -0
  107. package/dist/packlets/zip-file-tree/index.js.map +1 -0
  108. package/dist/packlets/zip-file-tree/zipFileTreeAccessors.js +2 -2
  109. package/dist/packlets/zip-file-tree/zipFileTreeAccessors.js.map +1 -0
  110. package/dist/packlets/zip-file-tree/zipFileTreeWriter.js.map +1 -0
  111. package/dist/ts-extras.d.ts +2869 -154
  112. package/dist/tsdoc-metadata.json +1 -1
  113. package/lib/index.browser.d.ts +4 -2
  114. package/lib/index.browser.d.ts.map +1 -0
  115. package/lib/index.browser.js +8 -3
  116. package/lib/index.browser.js.map +1 -0
  117. package/lib/index.d.ts.map +1 -0
  118. package/lib/index.js.map +1 -0
  119. package/lib/packlets/ai-assist/apiClient.d.ts +99 -16
  120. package/lib/packlets/ai-assist/apiClient.d.ts.map +1 -0
  121. package/lib/packlets/ai-assist/apiClient.js +961 -130
  122. package/lib/packlets/ai-assist/apiClient.js.map +1 -0
  123. package/lib/packlets/ai-assist/chatRequestBuilders.d.ts +89 -0
  124. package/lib/packlets/ai-assist/chatRequestBuilders.d.ts.map +1 -0
  125. package/lib/packlets/ai-assist/chatRequestBuilders.js +195 -0
  126. package/lib/packlets/ai-assist/chatRequestBuilders.js.map +1 -0
  127. package/lib/packlets/ai-assist/converters.d.ts.map +1 -0
  128. package/lib/packlets/ai-assist/converters.js +2 -1
  129. package/lib/packlets/ai-assist/converters.js.map +1 -0
  130. package/lib/packlets/ai-assist/endpoint.d.ts +28 -0
  131. package/lib/packlets/ai-assist/endpoint.d.ts.map +1 -0
  132. package/lib/packlets/ai-assist/endpoint.js +82 -0
  133. package/lib/packlets/ai-assist/endpoint.js.map +1 -0
  134. package/lib/packlets/ai-assist/imageOptionsResolver.d.ts +74 -0
  135. package/lib/packlets/ai-assist/imageOptionsResolver.d.ts.map +1 -0
  136. package/lib/packlets/ai-assist/imageOptionsResolver.js +216 -0
  137. package/lib/packlets/ai-assist/imageOptionsResolver.js.map +1 -0
  138. package/lib/packlets/ai-assist/index.d.ts +7 -3
  139. package/lib/packlets/ai-assist/index.d.ts.map +1 -0
  140. package/lib/packlets/ai-assist/index.js +21 -1
  141. package/lib/packlets/ai-assist/index.js.map +1 -0
  142. package/lib/packlets/ai-assist/jsonCompletion.d.ts +93 -0
  143. package/lib/packlets/ai-assist/jsonCompletion.d.ts.map +1 -0
  144. package/lib/packlets/ai-assist/jsonCompletion.js +99 -0
  145. package/lib/packlets/ai-assist/jsonCompletion.js.map +1 -0
  146. package/lib/packlets/ai-assist/jsonResponse.d.ts +91 -0
  147. package/lib/packlets/ai-assist/jsonResponse.d.ts.map +1 -0
  148. package/lib/packlets/ai-assist/jsonResponse.js +154 -0
  149. package/lib/packlets/ai-assist/jsonResponse.js.map +1 -0
  150. package/lib/packlets/ai-assist/model.d.ts +720 -7
  151. package/lib/packlets/ai-assist/model.d.ts.map +1 -0
  152. package/lib/packlets/ai-assist/model.js +22 -4
  153. package/lib/packlets/ai-assist/model.js.map +1 -0
  154. package/lib/packlets/ai-assist/registry.d.ts +34 -1
  155. package/lib/packlets/ai-assist/registry.d.ts.map +1 -0
  156. package/lib/packlets/ai-assist/registry.js +238 -11
  157. package/lib/packlets/ai-assist/registry.js.map +1 -0
  158. package/lib/packlets/ai-assist/sseParser.d.ts +45 -0
  159. package/lib/packlets/ai-assist/sseParser.d.ts.map +1 -0
  160. package/lib/packlets/ai-assist/sseParser.js +128 -0
  161. package/lib/packlets/ai-assist/sseParser.js.map +1 -0
  162. package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts +19 -0
  163. package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts.map +1 -0
  164. package/lib/packlets/ai-assist/streamingAdapters/anthropic.js +200 -0
  165. package/lib/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -0
  166. package/lib/packlets/ai-assist/streamingAdapters/common.d.ts +83 -0
  167. package/lib/packlets/ai-assist/streamingAdapters/common.d.ts.map +1 -0
  168. package/lib/packlets/ai-assist/streamingAdapters/common.js +83 -0
  169. package/lib/packlets/ai-assist/streamingAdapters/common.js.map +1 -0
  170. package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts +20 -0
  171. package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts.map +1 -0
  172. package/lib/packlets/ai-assist/streamingAdapters/gemini.js +175 -0
  173. package/lib/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -0
  174. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts +19 -0
  175. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts.map +1 -0
  176. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js +168 -0
  177. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -0
  178. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts +20 -0
  179. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts.map +1 -0
  180. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js +182 -0
  181. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -0
  182. package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts +34 -0
  183. package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts.map +1 -0
  184. package/lib/packlets/ai-assist/streamingAdapters/proxy.js +166 -0
  185. package/lib/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -0
  186. package/lib/packlets/ai-assist/streamingClient.d.ts +33 -0
  187. package/lib/packlets/ai-assist/streamingClient.d.ts.map +1 -0
  188. package/lib/packlets/ai-assist/streamingClient.js +121 -0
  189. package/lib/packlets/ai-assist/streamingClient.js.map +1 -0
  190. package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts +71 -0
  191. package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts.map +1 -0
  192. package/lib/packlets/ai-assist/thinkingOptionsResolver.js +270 -0
  193. package/lib/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -0
  194. package/lib/packlets/ai-assist/toolFormats.d.ts.map +1 -0
  195. package/lib/packlets/ai-assist/toolFormats.js.map +1 -0
  196. package/lib/packlets/conversion/converters.d.ts +8 -1
  197. package/lib/packlets/conversion/converters.d.ts.map +1 -0
  198. package/lib/packlets/conversion/converters.js +36 -2
  199. package/lib/packlets/conversion/converters.js.map +1 -0
  200. package/lib/packlets/conversion/index.d.ts.map +1 -0
  201. package/lib/packlets/conversion/index.js.map +1 -0
  202. package/lib/packlets/crypto-utils/constants.d.ts.map +1 -0
  203. package/lib/packlets/crypto-utils/constants.js.map +1 -0
  204. package/lib/packlets/crypto-utils/converters.d.ts +12 -1
  205. package/lib/packlets/crypto-utils/converters.d.ts.map +1 -0
  206. package/lib/packlets/crypto-utils/converters.js +25 -5
  207. package/lib/packlets/crypto-utils/converters.js.map +1 -0
  208. package/lib/packlets/crypto-utils/directEncryptionProvider.d.ts.map +1 -0
  209. package/lib/packlets/crypto-utils/directEncryptionProvider.js.map +1 -0
  210. package/lib/packlets/crypto-utils/encryptedFile.d.ts.map +1 -0
  211. package/lib/packlets/crypto-utils/encryptedFile.js.map +1 -0
  212. package/lib/packlets/crypto-utils/hpkeProvider.d.ts +142 -0
  213. package/lib/packlets/crypto-utils/hpkeProvider.d.ts.map +1 -0
  214. package/lib/packlets/crypto-utils/hpkeProvider.js +337 -0
  215. package/lib/packlets/crypto-utils/hpkeProvider.js.map +1 -0
  216. package/lib/packlets/crypto-utils/index.browser.d.ts +3 -0
  217. package/lib/packlets/crypto-utils/index.browser.d.ts.map +1 -0
  218. package/lib/packlets/crypto-utils/index.browser.js +14 -1
  219. package/lib/packlets/crypto-utils/index.browser.js.map +1 -0
  220. package/lib/packlets/crypto-utils/index.d.ts +3 -0
  221. package/lib/packlets/crypto-utils/index.d.ts.map +1 -0
  222. package/lib/packlets/crypto-utils/index.js +13 -1
  223. package/lib/packlets/crypto-utils/index.js.map +1 -0
  224. package/lib/packlets/crypto-utils/keyPairAlgorithmParams.d.ts +54 -0
  225. package/lib/packlets/crypto-utils/keyPairAlgorithmParams.d.ts.map +1 -0
  226. package/lib/packlets/crypto-utils/keyPairAlgorithmParams.js +74 -0
  227. package/lib/packlets/crypto-utils/keyPairAlgorithmParams.js.map +1 -0
  228. package/lib/packlets/crypto-utils/keystore/converters.d.ts +68 -6
  229. package/lib/packlets/crypto-utils/keystore/converters.d.ts.map +1 -0
  230. package/lib/packlets/crypto-utils/keystore/converters.js +101 -9
  231. package/lib/packlets/crypto-utils/keystore/converters.js.map +1 -0
  232. package/lib/packlets/crypto-utils/keystore/index.d.ts +1 -0
  233. package/lib/packlets/crypto-utils/keystore/index.d.ts.map +1 -0
  234. package/lib/packlets/crypto-utils/keystore/index.js +1 -0
  235. package/lib/packlets/crypto-utils/keystore/index.js.map +1 -0
  236. package/lib/packlets/crypto-utils/keystore/keyStore.d.ts +198 -13
  237. package/lib/packlets/crypto-utils/keystore/keyStore.d.ts.map +1 -0
  238. package/lib/packlets/crypto-utils/keystore/keyStore.js +624 -124
  239. package/lib/packlets/crypto-utils/keystore/keyStore.js.map +1 -0
  240. package/lib/packlets/crypto-utils/keystore/model.d.ts +268 -19
  241. package/lib/packlets/crypto-utils/keystore/model.d.ts.map +1 -0
  242. package/lib/packlets/crypto-utils/keystore/model.js +24 -2
  243. package/lib/packlets/crypto-utils/keystore/model.js.map +1 -0
  244. package/lib/packlets/crypto-utils/keystore/privateKeyStorage.d.ts +50 -0
  245. package/lib/packlets/crypto-utils/keystore/privateKeyStorage.d.ts.map +1 -0
  246. package/lib/packlets/crypto-utils/keystore/privateKeyStorage.js +22 -0
  247. package/lib/packlets/crypto-utils/keystore/privateKeyStorage.js.map +1 -0
  248. package/lib/packlets/crypto-utils/model.d.ts +338 -10
  249. package/lib/packlets/crypto-utils/model.d.ts.map +1 -0
  250. package/lib/packlets/crypto-utils/model.js +33 -1
  251. package/lib/packlets/crypto-utils/model.js.map +1 -0
  252. package/lib/packlets/crypto-utils/nodeCryptoProvider.d.ts +110 -2
  253. package/lib/packlets/crypto-utils/nodeCryptoProvider.d.ts.map +1 -0
  254. package/lib/packlets/crypto-utils/nodeCryptoProvider.js +269 -0
  255. package/lib/packlets/crypto-utils/nodeCryptoProvider.js.map +1 -0
  256. package/lib/packlets/crypto-utils/spkiHelpers.d.ts +53 -0
  257. package/lib/packlets/crypto-utils/spkiHelpers.d.ts.map +1 -0
  258. package/lib/packlets/crypto-utils/spkiHelpers.js +136 -0
  259. package/lib/packlets/crypto-utils/spkiHelpers.js.map +1 -0
  260. package/lib/packlets/csv/csvFileHelpers.d.ts +0 -10
  261. package/lib/packlets/csv/csvFileHelpers.d.ts.map +1 -0
  262. package/lib/packlets/csv/csvFileHelpers.js +0 -15
  263. package/lib/packlets/csv/csvFileHelpers.js.map +1 -0
  264. package/lib/packlets/csv/csvHelpers.d.ts +10 -0
  265. package/lib/packlets/csv/csvHelpers.d.ts.map +1 -0
  266. package/lib/packlets/csv/csvHelpers.js +15 -0
  267. package/lib/packlets/csv/csvHelpers.js.map +1 -0
  268. package/lib/packlets/csv/index.browser.d.ts +0 -1
  269. package/lib/packlets/csv/index.browser.d.ts.map +1 -0
  270. package/lib/packlets/csv/index.browser.js +1 -5
  271. package/lib/packlets/csv/index.browser.js.map +1 -0
  272. package/lib/packlets/csv/index.d.ts.map +1 -0
  273. package/lib/packlets/csv/index.js.map +1 -0
  274. package/lib/packlets/experimental/extendedArray.d.ts.map +1 -0
  275. package/lib/packlets/experimental/extendedArray.js.map +1 -0
  276. package/lib/packlets/experimental/formatter.d.ts.map +1 -0
  277. package/lib/packlets/experimental/formatter.js.map +1 -0
  278. package/lib/packlets/experimental/index.d.ts.map +1 -0
  279. package/lib/packlets/experimental/index.js.map +1 -0
  280. package/lib/packlets/experimental/rangeOf.d.ts.map +1 -0
  281. package/lib/packlets/experimental/rangeOf.js.map +1 -0
  282. package/lib/packlets/hash/index.browser.d.ts.map +1 -0
  283. package/lib/packlets/hash/index.browser.js.map +1 -0
  284. package/lib/packlets/hash/index.d.ts.map +1 -0
  285. package/lib/packlets/hash/index.js.map +1 -0
  286. package/lib/packlets/hash/index.node.d.ts.map +1 -0
  287. package/lib/packlets/hash/index.node.js.map +1 -0
  288. package/lib/packlets/hash/md5Normalizer.browser.d.ts.map +1 -0
  289. package/lib/packlets/hash/md5Normalizer.browser.js.map +1 -0
  290. package/lib/packlets/hash/md5Normalizer.d.ts.map +1 -0
  291. package/lib/packlets/hash/md5Normalizer.js.map +1 -0
  292. package/lib/packlets/mustache/index.d.ts +1 -1
  293. package/lib/packlets/mustache/index.d.ts.map +1 -0
  294. package/lib/packlets/mustache/index.js.map +1 -0
  295. package/lib/packlets/mustache/interfaces.d.ts +34 -0
  296. package/lib/packlets/mustache/interfaces.d.ts.map +1 -0
  297. package/lib/packlets/mustache/interfaces.js.map +1 -0
  298. package/lib/packlets/mustache/mustacheTemplate.d.ts +2 -0
  299. package/lib/packlets/mustache/mustacheTemplate.d.ts.map +1 -0
  300. package/lib/packlets/mustache/mustacheTemplate.js +42 -4
  301. package/lib/packlets/mustache/mustacheTemplate.js.map +1 -0
  302. package/lib/packlets/record-jar/index.browser.d.ts +0 -1
  303. package/lib/packlets/record-jar/index.browser.d.ts.map +1 -0
  304. package/lib/packlets/record-jar/index.browser.js +1 -5
  305. package/lib/packlets/record-jar/index.browser.js.map +1 -0
  306. package/lib/packlets/record-jar/index.d.ts.map +1 -0
  307. package/lib/packlets/record-jar/index.js.map +1 -0
  308. package/lib/packlets/record-jar/recordJarFileHelpers.d.ts +0 -11
  309. package/lib/packlets/record-jar/recordJarFileHelpers.d.ts.map +1 -0
  310. package/lib/packlets/record-jar/recordJarFileHelpers.js +0 -19
  311. package/lib/packlets/record-jar/recordJarFileHelpers.js.map +1 -0
  312. package/lib/packlets/record-jar/recordJarHelpers.d.ts +11 -0
  313. package/lib/packlets/record-jar/recordJarHelpers.d.ts.map +1 -0
  314. package/lib/packlets/record-jar/recordJarHelpers.js +19 -0
  315. package/lib/packlets/record-jar/recordJarHelpers.js.map +1 -0
  316. package/lib/packlets/yaml/converters.d.ts.map +1 -0
  317. package/lib/packlets/yaml/converters.js.map +1 -0
  318. package/lib/packlets/yaml/index.d.ts +1 -0
  319. package/lib/packlets/yaml/index.d.ts.map +1 -0
  320. package/lib/packlets/yaml/index.js +1 -0
  321. package/lib/packlets/yaml/index.js.map +1 -0
  322. package/lib/packlets/yaml/serializers.d.ts +45 -0
  323. package/lib/packlets/yaml/serializers.d.ts.map +1 -0
  324. package/lib/packlets/yaml/serializers.js +84 -0
  325. package/lib/packlets/yaml/serializers.js.map +1 -0
  326. package/lib/packlets/zip-file-tree/index.d.ts.map +1 -0
  327. package/lib/packlets/zip-file-tree/index.js.map +1 -0
  328. package/lib/packlets/zip-file-tree/zipFileTreeAccessors.d.ts +2 -2
  329. package/lib/packlets/zip-file-tree/zipFileTreeAccessors.d.ts.map +1 -0
  330. package/lib/packlets/zip-file-tree/zipFileTreeAccessors.js +2 -2
  331. package/lib/packlets/zip-file-tree/zipFileTreeAccessors.js.map +1 -0
  332. package/lib/packlets/zip-file-tree/zipFileTreeWriter.d.ts.map +1 -0
  333. package/lib/packlets/zip-file-tree/zipFileTreeWriter.js.map +1 -0
  334. package/package.json +16 -15
@@ -0,0 +1 @@
1
+ {"version":3,"file":"converters.js","sourceRoot":"","sources":["../../../src/packlets/crypto-utils/converters.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2024 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 { Converters as JsonConverters, JsonValue } from '@fgv/ts-json-base';\nimport { Converter, Converters, fail, succeed } from '@fgv/ts-utils';\nimport * as Constants from './constants';\nimport {\n EncryptedFileErrorMode,\n EncryptedFileFormat,\n EncryptionAlgorithm,\n IArgon2idKeyDerivationParams,\n IEncryptedFile,\n IKeyDerivationParams,\n INamedSecret,\n IPbkdf2KeyDerivationParams,\n KeyDerivationFunction\n} from './model';\n\n// ============================================================================\n// Base Converters\n// ============================================================================\n\n/**\n * Converter for {@link CryptoUtils.EncryptionAlgorithm | encryption algorithm} values.\n * @public\n */\nexport const encryptionAlgorithm: Converter<EncryptionAlgorithm> =\n Converters.enumeratedValue<EncryptionAlgorithm>([Constants.DEFAULT_ALGORITHM]);\n\n/**\n * Converter for {@link CryptoUtils.EncryptedFileFormat | encrypted file format} version.\n * @public\n */\nexport const encryptedFileFormat: Converter<EncryptedFileFormat> = Converters.enumeratedValue([\n Constants.ENCRYPTED_FILE_FORMAT\n]);\n\n/**\n * Converter for {@link CryptoUtils.EncryptedFileErrorMode | encrypted file error mode}.\n * @public\n */\nexport const encryptedFileErrorMode: Converter<EncryptedFileErrorMode> =\n Converters.enumeratedValue<EncryptedFileErrorMode>(['fail', 'skip', 'warn']);\n\n/**\n * Converter for {@link CryptoUtils.KeyDerivationFunction | key derivation function} type.\n * @public\n */\nexport const keyDerivationFunction: Converter<KeyDerivationFunction> =\n Converters.enumeratedValue<KeyDerivationFunction>(['pbkdf2', 'argon2id']);\n\n/**\n * Converter for {@link CryptoUtils.IPbkdf2KeyDerivationParams | PBKDF2 key derivation parameters}.\n * @public\n */\nexport const pbkdf2KeyDerivationParams: Converter<IPbkdf2KeyDerivationParams> =\n Converters.object<IPbkdf2KeyDerivationParams>({\n kdf: Converters.enumeratedValue<'pbkdf2'>(['pbkdf2']),\n salt: Converters.string,\n iterations: Converters.number\n });\n\n/**\n * Converter for {@link CryptoUtils.IArgon2idKeyDerivationParams | Argon2id key derivation parameters}.\n * @public\n */\nexport const argon2idKeyDerivationParams: Converter<IArgon2idKeyDerivationParams> =\n Converters.object<IArgon2idKeyDerivationParams>({\n kdf: Converters.enumeratedValue<'argon2id'>(['argon2id']),\n salt: Converters.string,\n memoryKiB: Converters.number,\n iterations: Converters.number,\n parallelism: Converters.number\n });\n\n/**\n * Converter for {@link CryptoUtils.IKeyDerivationParams | key derivation parameters}.\n * Handles both PBKDF2 and Argon2id discriminated union arms.\n * @public\n */\nexport const keyDerivationParams: Converter<IKeyDerivationParams> = Converters.oneOf<IKeyDerivationParams>([\n pbkdf2KeyDerivationParams,\n argon2idKeyDerivationParams\n]);\n\n/**\n * Converter for base64 strings (validates format).\n * @public\n */\nexport const base64String: Converter<string> = Converters.string.withConstraint((value) => {\n // Basic base64 validation - check for valid characters and padding\n const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;\n if (!base64Regex.test(value)) {\n return fail('Invalid base64 encoding');\n }\n return succeed(value);\n});\n\n// ============================================================================\n// Uint8Array Converter\n// ============================================================================\n\n/**\n * Converter which converts a base64 string to a Uint8Array.\n * @public\n */\nexport const uint8ArrayFromBase64: Converter<Uint8Array> = Converters.string.map((base64) => {\n try {\n // Use Buffer in Node.js environment, atob in browser\n if (typeof Buffer !== 'undefined') {\n return succeed(Uint8Array.from(Buffer.from(base64, 'base64')));\n }\n /* c8 ignore start - Browser-only fallback cannot be tested in Node.js environment */\n const binaryString = atob(base64);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return succeed(bytes);\n } catch (e) {\n // This catch is for browser's atob() which throws on invalid base64\n // Node's Buffer.from() doesn't throw, it ignores invalid characters\n const message = e instanceof Error ? e.message : String(e);\n return fail(`Invalid base64: ${message}`);\n }\n /* c8 ignore stop */\n});\n\n// ============================================================================\n// Named Secret Converter\n// ============================================================================\n\n/**\n * Converter for {@link CryptoUtils.INamedSecret | named secret} from JSON representation.\n * Expects key as base64 string in JSON, converts to Uint8Array.\n * @public\n */\nexport const namedSecret: Converter<INamedSecret> = Converters.object<INamedSecret>({\n name: Converters.string,\n key: uint8ArrayFromBase64\n});\n\n// ============================================================================\n// Encrypted File Converter Factory\n// ============================================================================\n\n/**\n * Base encrypted file structure without metadata typing.\n * Used internally by the converter factory.\n */\ninterface IBaseEncryptedFile {\n readonly format: EncryptedFileFormat;\n readonly secretName: string;\n readonly algorithm: EncryptionAlgorithm;\n readonly iv: string;\n readonly authTag: string;\n readonly encryptedData: string;\n readonly keyDerivation?: IKeyDerivationParams;\n readonly metadata?: JsonValue;\n}\n\n/**\n * Base converter for encrypted file structure (without typed metadata).\n */\nconst baseEncryptedFileConverter: Converter<IBaseEncryptedFile> = Converters.object<IBaseEncryptedFile>(\n {\n format: encryptedFileFormat,\n secretName: Converters.string,\n algorithm: encryptionAlgorithm,\n iv: base64String,\n authTag: base64String,\n encryptedData: base64String,\n keyDerivation: keyDerivationParams,\n metadata: JsonConverters.jsonValue\n },\n { optionalFields: ['keyDerivation', 'metadata'] }\n);\n\n/**\n * Creates a converter for {@link CryptoUtils.IEncryptedFile | encrypted files} with optional typed metadata.\n * @typeParam TMetadata - Type of optional unencrypted metadata\n * @param metadataConverter - Optional converter for validating metadata field\n * @returns A converter that validates and converts encrypted file structures\n * @public\n */\nexport function createEncryptedFileConverter<TMetadata = JsonValue>(\n metadataConverter?: Converter<TMetadata>\n): Converter<IEncryptedFile<TMetadata>> {\n return Converters.generic<IEncryptedFile<TMetadata>>((from: unknown) => {\n // First validate base structure\n const baseResult = baseEncryptedFileConverter.convert(from);\n if (baseResult.isFailure()) {\n return fail(baseResult.message);\n }\n\n const base = baseResult.value;\n\n // Validate metadata with specific converter if provided and metadata exists\n if (metadataConverter !== undefined && base.metadata !== undefined) {\n const metaResult = metadataConverter.convert(base.metadata);\n if (metaResult.isFailure()) {\n return fail(`Invalid metadata: ${metaResult.message}`);\n }\n return succeed({\n ...base,\n metadata: metaResult.value\n } as IEncryptedFile<TMetadata>);\n }\n\n // Return as-is (metadata is either undefined or untyped JsonValue)\n return succeed(base as IEncryptedFile<TMetadata>);\n });\n}\n\n/**\n * Default converter for encrypted files without typed metadata.\n * @public\n */\nexport const encryptedFile: Converter<IEncryptedFile> = createEncryptedFileConverter();\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directEncryptionProvider.js","sourceRoot":"","sources":["../../../src/packlets/crypto-utils/directEncryptionProvider.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;AAGZ,OAAO,EAAU,IAAI,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AA0BtD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,OAAO,wBAAwB;IAKnC,YAAoB,MAAuC;QACzD,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC,cAAc,CAAC;QAC7C,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC;QACvB,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,eAAe,CAAC;IACjD,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,MAAM,CAAC,MAAuC;QAC1D,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC,gCAAgC,CAAC,CAAC;QAChD,CAAC;QACD,OAAO,OAAO,CAAC,IAAI,wBAAwB,CAAC,MAAM,CAAC,CAAC,CAAC;IACvD,CAAC;IAED;;;OAGG;IACH,IAAW,eAAe;QACxB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,aAAa,CACxB,UAAkB,EAClB,OAAkB,EAClB,QAAoB;QAEpB,IAAI,IAAI,CAAC,gBAAgB,KAAK,SAAS,IAAI,UAAU,KAAK,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAChF,OAAO,IAAI,CACT,oCAAoC,UAAU,+BAA+B,IAAI,CAAC,gBAAgB,GAAG,CACtG,CAAC;QACJ,CAAC;QAED,OAAO,mBAAmB,CAAC;YACzB,OAAO;YACP,UAAU;YACV,GAAG,EAAE,IAAI,CAAC,IAAI;YACd,cAAc,EAAE,IAAI,CAAC,eAAe;YACpC,QAAQ;SACT,CAAC,CAAC;IACL,CAAC;CACF","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 { JsonValue } from '@fgv/ts-json-base';\nimport { Result, fail, succeed } from '@fgv/ts-utils';\nimport { createEncryptedFile } from './encryptedFile';\nimport { ICryptoProvider, IEncryptedFile, IEncryptionProvider } from './model';\n\n/**\n * Parameters for creating a {@link DirectEncryptionProvider}.\n * @public\n */\nexport interface IDirectEncryptionProviderParams {\n /**\n * The crypto provider to use for encryption operations.\n */\n readonly cryptoProvider: ICryptoProvider;\n\n /**\n * The encryption key (32 bytes for AES-256).\n */\n readonly key: Uint8Array;\n\n /**\n * Optional bound secret name.\n * When set, `encryptByName` will fail if called with a different name.\n * When unset, any secret name is accepted.\n */\n readonly boundSecretName?: string;\n}\n\n/**\n * An {@link IEncryptionProvider} that uses a pre-supplied key and crypto provider.\n *\n * This is useful when you have the raw encryption key from an external source\n * (e.g. a `SecretProvider` callback, password derivation, or a one-shot\n * operation) and don't want to open a full KeyStore.\n *\n * Optionally bound to a specific secret name for safety: if a `boundSecretName`\n * is provided, calls to `encryptByName` with a different name will fail.\n *\n * @example\n * ```typescript\n * const provider = DirectEncryptionProvider.create({\n * cryptoProvider: nodeCryptoProvider,\n * key: myKey,\n * boundSecretName: 'my-collection'\n * }).orThrow();\n *\n * const encrypted = await provider.encryptByName('my-collection', jsonContent);\n * ```\n *\n * @public\n */\nexport class DirectEncryptionProvider implements IEncryptionProvider {\n private readonly _cryptoProvider: ICryptoProvider;\n private readonly _key: Uint8Array;\n private readonly _boundSecretName: string | undefined;\n\n private constructor(params: IDirectEncryptionProviderParams) {\n this._cryptoProvider = params.cryptoProvider;\n this._key = params.key;\n this._boundSecretName = params.boundSecretName;\n }\n\n /**\n * Creates a new DirectEncryptionProvider.\n * @param params - Provider configuration\n * @returns Success with provider, or Failure if parameters are invalid\n * @public\n */\n public static create(params: IDirectEncryptionProviderParams): Result<DirectEncryptionProvider> {\n if (params.key.length === 0) {\n return fail('Encryption key cannot be empty');\n }\n return succeed(new DirectEncryptionProvider(params));\n }\n\n /**\n * The secret name this provider is bound to, if any.\n * @public\n */\n public get boundSecretName(): string | undefined {\n return this._boundSecretName;\n }\n\n /**\n * {@inheritDoc IEncryptionProvider.encryptByName}\n */\n public async encryptByName<TMetadata = JsonValue>(\n secretName: string,\n content: JsonValue,\n metadata?: TMetadata\n ): Promise<Result<IEncryptedFile<TMetadata>>> {\n if (this._boundSecretName !== undefined && secretName !== this._boundSecretName) {\n return fail(\n `Secret name mismatch: requested '${secretName}' but provider is bound to '${this._boundSecretName}'`\n );\n }\n\n return createEncryptedFile({\n content,\n secretName,\n key: this._key,\n cryptoProvider: this._cryptoProvider,\n metadata\n });\n }\n}\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryptedFile.js","sourceRoot":"","sources":["../../../src/packlets/crypto-utils/encryptedFile.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2024 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 { JsonValue } from '@fgv/ts-json-base';\nimport { captureResult, Converter, fail, Result, succeed } from '@fgv/ts-utils';\nimport * as Constants from './constants';\nimport { createEncryptedFileConverter } from './converters';\nimport { ICryptoProvider, IEncryptedFile, IKeyDerivationParams, isEncryptedFile } from './model';\n\n// ============================================================================\n// Base64 Utilities\n// ============================================================================\n\n/**\n * Encodes a `Uint8Array` to a base64 string.\n * @param bytes - Bytes to encode\n * @returns Base64 string\n * @public\n */\n/* c8 ignore start - Browser-only fallback cannot be tested in Node.js environment */\nexport function toBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(bytes).toString('base64');\n }\n // Browser fallback\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n/* c8 ignore stop */\n\n/**\n * Decodes a base64 string to a `Uint8Array`.\n * @param base64 - Base64 string to decode\n * @returns Decoded bytes\n * @public\n */\n/* c8 ignore start - Browser-only fallback cannot be tested in Node.js environment */\nexport function fromBase64(base64: string): Uint8Array {\n if (typeof Buffer !== 'undefined') {\n return new Uint8Array(Buffer.from(base64, 'base64'));\n }\n // Browser fallback\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n/* c8 ignore stop */\n\n// ============================================================================\n// Create Encrypted File Parameters\n// ============================================================================\n\n/**\n * Parameters for creating an {@link CryptoUtils.IEncryptedFile | encrypted file}.\n * @typeParam TMetadata - Type of optional unencrypted metadata\n * @public\n */\nexport interface ICreateEncryptedFileParams<TMetadata = JsonValue> {\n /**\n * The JSON content to encrypt.\n */\n readonly content: JsonValue;\n\n /**\n * Name of the secret used for encryption.\n */\n readonly secretName: string;\n\n /**\n * The encryption key (32 bytes for AES-256).\n */\n readonly key: Uint8Array;\n\n /**\n * {@link CryptoUtils.ICryptoProvider | Crypto provider} to use for encryption.\n */\n readonly cryptoProvider: ICryptoProvider;\n\n /**\n * Optional metadata to include unencrypted.\n */\n readonly metadata?: TMetadata;\n\n /**\n * Optional converter to validate metadata before including.\n * If provided, metadata will be validated before encryption.\n */\n readonly metadataConverter?: Converter<TMetadata>;\n\n /**\n * Optional {@link CryptoUtils.IKeyDerivationParams | key derivation parameters}.\n * If provided, stores the salt and iterations used to derive the key from a password.\n * This allows decryption using only a password (the salt/iterations are read from the file).\n */\n readonly keyDerivation?: IKeyDerivationParams;\n}\n\n// ============================================================================\n// Encryption Functions\n// ============================================================================\n\n/**\n * Creates an {@link CryptoUtils.IEncryptedFile | encrypted file} from JSON content.\n * @typeParam TMetadata - Type of optional unencrypted metadata\n * @param params - Encryption parameters\n * @returns `Success` with encrypted file structure, or `Failure` with an error.\n * @public\n */\nexport async function createEncryptedFile<TMetadata = JsonValue>(\n params: ICreateEncryptedFileParams<TMetadata>\n): Promise<Result<IEncryptedFile<TMetadata>>> {\n const { content, secretName, key, metadata, metadataConverter, keyDerivation, cryptoProvider } = params;\n\n // Validate metadata if converter provided\n /* c8 ignore next 6 - metadata validation path exercised via higher-level tests */\n if (metadata !== undefined && metadataConverter !== undefined) {\n const metadataResult = metadataConverter.convert(metadata);\n if (metadataResult.isFailure()) {\n return fail(`Invalid metadata: ${metadataResult.message}`);\n }\n }\n\n // Serialize content to JSON string\n const jsonResult = captureResult(() => JSON.stringify(content));\n if (jsonResult.isFailure()) {\n return fail(`Failed to serialize content: ${jsonResult.message}`);\n }\n\n // Encrypt the JSON string\n const encryptResult = await cryptoProvider.encrypt(jsonResult.value, key);\n if (encryptResult.isFailure()) {\n return fail(`Encryption failed: ${encryptResult.message}`);\n }\n\n const { iv, authTag, encryptedData } = encryptResult.value;\n\n // Build the encrypted file structure\n const encryptedFile: IEncryptedFile<TMetadata> = {\n format: Constants.ENCRYPTED_FILE_FORMAT,\n secretName,\n algorithm: Constants.DEFAULT_ALGORITHM,\n iv: toBase64(iv),\n authTag: toBase64(authTag),\n encryptedData: toBase64(encryptedData),\n ...(metadata !== undefined ? { metadata } : {}),\n ...(keyDerivation !== undefined ? { keyDerivation } : {})\n };\n\n return succeed(encryptedFile);\n}\n\n// ============================================================================\n// Decryption Functions\n// ============================================================================\n\n/**\n * Decrypts an {@link CryptoUtils.IEncryptedFile | encrypted file} and returns the JSON content.\n * @typeParam TPayload - Expected type of decrypted content\n * @param file - The encrypted file structure\n * @param key - The decryption key (32 bytes for AES-256)\n * @param cryptoProvider - {@link CryptoUtils.ICryptoProvider | Crypto provider} to use for decryption\n * @param payloadConverter - Optional converter to validate and convert decrypted content\n * @returns `Success` with decrypted content, or `Failure` with an error.\n * @public\n */\nexport async function decryptFile<TPayload extends JsonValue = JsonValue>(\n file: IEncryptedFile<unknown>,\n key: Uint8Array,\n cryptoProvider: ICryptoProvider,\n payloadConverter?: Converter<TPayload>\n): Promise<Result<TPayload>> {\n // Decode base64 values\n const iv = fromBase64(file.iv);\n const authTag = fromBase64(file.authTag);\n const encryptedData = fromBase64(file.encryptedData);\n\n // Decrypt\n const decryptResult = await cryptoProvider.decrypt(encryptedData, key, iv, authTag);\n if (decryptResult.isFailure()) {\n return fail(decryptResult.message);\n }\n\n // Parse JSON\n const parseResult = captureResult(() => JSON.parse(decryptResult.value) as TPayload).withErrorFormat(\n (e) => `Failed to parse decrypted content as JSON: ${e}`\n );\n\n /* c8 ignore next 3 - JSON parse failure only occurs with corrupted encrypted data */\n if (parseResult.isFailure()) {\n return parseResult;\n }\n\n // Validate with converter if provided\n /* c8 ignore next 3 - payload converter path exercised via higher-level tests */\n if (payloadConverter !== undefined) {\n return payloadConverter.convert(parseResult.value);\n }\n\n return parseResult;\n}\n\n/**\n * Attempts to parse and decrypt a JSON object as an {@link CryptoUtils.IEncryptedFile | encrypted file}.\n * @typeParam TPayload - Expected type of decrypted content\n * @typeParam TMetadata - Type of optional unencrypted metadata\n * @param json - JSON object that may be an encrypted file\n * @param key - The decryption key (32 bytes for AES-256)\n * @param cryptoProvider - {@link CryptoUtils.ICryptoProvider | Crypto provider} to use for decryption\n * @param payloadConverter - Optional converter to validate and convert decrypted content\n * @param metadataConverter - Optional converter to validate metadata before decryption\n * @returns `Success` with decrypted content, or `Failure` with an error (including if not encrypted)\n * @public\n */\nexport async function tryDecryptFile<TPayload extends JsonValue = JsonValue, TMetadata = JsonValue>(\n json: JsonValue,\n key: Uint8Array,\n cryptoProvider: ICryptoProvider,\n payloadConverter?: Converter<TPayload>,\n metadataConverter?: Converter<TMetadata>\n): Promise<Result<TPayload>> {\n // Check if it's an encrypted file\n if (!isEncryptedFile(json)) {\n return fail('Not an encrypted file');\n }\n\n // Validate and convert to typed encrypted file\n const fileConverter = createEncryptedFileConverter(metadataConverter);\n const fileResult = fileConverter.convert(json);\n if (fileResult.isFailure()) {\n return fail(`Invalid encrypted file format: ${fileResult.message}`);\n }\n\n return decryptFile(fileResult.value, key, cryptoProvider, payloadConverter);\n}\n"]}
@@ -0,0 +1,333 @@
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 { captureAsyncResult, captureResult, fail, succeed } from '@fgv/ts-utils';
21
+ // ---- Internal constants ----
22
+ // "HPKE-v1" (7 bytes) — RFC 9180 domain separator prefix
23
+ const _HPKE_VERSION = new Uint8Array([0x48, 0x50, 0x4b, 0x45, 0x2d, 0x76, 0x31]);
24
+ // suite_id = "HPKE" || I2OSP(KEM_ID=0x0020, 2) || I2OSP(KDF_ID=0x0001, 2) || I2OSP(AEAD_ID=0x0002, 2)
25
+ // Used in key schedule LabeledExtract/LabeledExpand calls.
26
+ const _SUITE_ID = new Uint8Array([
27
+ 0x48, 0x50, 0x4b, 0x45, 0x00, 0x20, 0x00, 0x01, 0x00, 0x02
28
+ ]);
29
+ // kem_suite_id = "KEM" || I2OSP(KEM_ID=0x0020, 2)
30
+ // Used in DHKEM-internal LabeledExtract/LabeledExpand calls.
31
+ const _KEM_SUITE_ID = new Uint8Array([0x4b, 0x45, 0x4d, 0x00, 0x20]);
32
+ const _N_SECRET = 32; // Nsecret: KEM shared-secret output length
33
+ const _N_PK = 32; // Npk: X25519 public key (raw) length — also the enc length
34
+ const _N_K = 32; // Nk: AES-256-GCM key length
35
+ const _N_N = 12; // Nn: AES-256-GCM nonce length
36
+ const _N_T = 16; // Nt: AES-256-GCM authentication tag length
37
+ const _MODE_BASE = 0x00; // RFC 9180 mode_base
38
+ // ---- Internal helpers ----
39
+ // These are NOT exported. Per design D7, only the five public operations are public surface.
40
+ // Copies any Uint8Array into a fresh Uint8Array<ArrayBuffer>.
41
+ // Required to satisfy TypeScript's strict BufferSource typing for Web Crypto API calls —
42
+ // subtle.* rejects Uint8Array<ArrayBufferLike> but accepts Uint8Array<ArrayBuffer>.
43
+ // Pattern follows browserCryptoProvider.ts toBufferView.
44
+ function _toBufferView(arr) {
45
+ const buffer = new ArrayBuffer(arr.byteLength);
46
+ const view = new Uint8Array(buffer);
47
+ view.set(arr);
48
+ return view;
49
+ }
50
+ function _concat(...arrays) {
51
+ const total = arrays.reduce((n, a) => n + a.length, 0);
52
+ const buffer = new ArrayBuffer(total);
53
+ const out = new Uint8Array(buffer);
54
+ let offset = 0;
55
+ for (const a of arrays) {
56
+ out.set(a, offset);
57
+ offset += a.length;
58
+ }
59
+ return out;
60
+ }
61
+ function _i2osp(value, length) {
62
+ const buffer = new ArrayBuffer(length);
63
+ const out = new Uint8Array(buffer);
64
+ for (let i = length - 1; i >= 0; i--) {
65
+ out[i] = value % 256;
66
+ value = Math.floor(value / 256);
67
+ }
68
+ return out;
69
+ }
70
+ // Decodes a base64url-encoded string to Uint8Array<ArrayBuffer>.
71
+ // Uses `atob` (global in Node 18+ and all modern browsers; no import needed).
72
+ function _base64UrlDecode(s) {
73
+ const base64 = s.replace(/-/g, '+').replace(/_/g, '/');
74
+ const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);
75
+ const binary = atob(padded);
76
+ const buffer = new ArrayBuffer(binary.length);
77
+ const out = new Uint8Array(buffer);
78
+ for (let i = 0; i < binary.length; i++) {
79
+ out[i] = binary.charCodeAt(i);
80
+ }
81
+ return out;
82
+ }
83
+ // HMAC-SHA256(key, data) — the underlying primitive for HKDF.
84
+ async function _hmacSha256(subtle, key, data) {
85
+ const hmacKey = await subtle.importKey('raw', _toBufferView(key), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
86
+ return new Uint8Array(await subtle.sign('HMAC', hmacKey, _toBufferView(data)));
87
+ }
88
+ // RFC 5869 HKDF-Extract(salt, IKM) = HMAC-SHA256(key=salt, msg=IKM).
89
+ // If salt is empty (length 0), uses 32 zero bytes per RFC 5869 §2.2.
90
+ async function _hkdfExtract(subtle, salt, ikm) {
91
+ const effectiveSalt = salt.length === 0 ? new Uint8Array(32) : salt;
92
+ return _hmacSha256(subtle, effectiveSalt, ikm);
93
+ }
94
+ // RFC 5869 HKDF-Expand(PRK, info, L) — iterative HMAC expansion.
95
+ async function _hkdfExpand(subtle, prk, info, length) {
96
+ if (length > 255 * 32) {
97
+ throw new Error(`HKDF-Expand: requested length ${length} exceeds maximum 8160 bytes (255 * HashLen)`);
98
+ }
99
+ const n = Math.ceil(length / 32);
100
+ const buffer = new ArrayBuffer(length);
101
+ const okm = new Uint8Array(buffer);
102
+ let prev = new Uint8Array(new ArrayBuffer(0));
103
+ let offset = 0;
104
+ for (let i = 1; i <= n; i++) {
105
+ prev = await _hmacSha256(subtle, prk, _concat(prev, info, new Uint8Array([i])));
106
+ const toCopy = Math.min(32, length - offset);
107
+ okm.set(prev.subarray(0, toCopy), offset);
108
+ offset += toCopy;
109
+ }
110
+ return okm;
111
+ }
112
+ // RFC 9180 §4 LabeledExtract — HKDF-Extract with HPKE-v1 domain label.
113
+ // labeled_ikm = "HPKE-v1" || suite_id || label || ikm
114
+ // Extract(salt, labeled_ikm)
115
+ async function _labeledExtract(subtle, suiteId, salt, label, ikm) {
116
+ const labeledIkm = _concat(_HPKE_VERSION, suiteId, new TextEncoder().encode(label), ikm);
117
+ return _hkdfExtract(subtle, salt, labeledIkm);
118
+ }
119
+ // RFC 9180 §4 LabeledExpand — HKDF-Expand with HPKE-v1 domain label.
120
+ // labeled_info = I2OSP(L, 2) || "HPKE-v1" || suite_id || label || info
121
+ // Expand(prk, labeled_info, L)
122
+ async function _labeledExpand(subtle, suiteId, prk, label, info, length) {
123
+ const labeledInfo = _concat(_i2osp(length, 2), _HPKE_VERSION, suiteId, new TextEncoder().encode(label), info);
124
+ return _hkdfExpand(subtle, prk, labeledInfo, length);
125
+ }
126
+ // RFC 9180 §4.1 DHKEM Encap — generates ephemeral keypair, DH with recipient pubkey,
127
+ // derives shared_secret via ExtractAndExpand.
128
+ // NOTE: uses label "eae_prk" (not "dh") per RFC 9180 §4.1 ExtractAndExpand.
129
+ async function _kemEncap(subtle, recipientPublicKey) {
130
+ const ephemeral = (await subtle.generateKey({ name: 'X25519' }, true, ['deriveBits']));
131
+ const enc = new Uint8Array(await subtle.exportKey('raw', ephemeral.publicKey));
132
+ const dh = new Uint8Array(await subtle.deriveBits({ name: 'X25519', public: recipientPublicKey }, ephemeral.privateKey, 256));
133
+ const pkRm = new Uint8Array(await subtle.exportKey('raw', recipientPublicKey));
134
+ const kemContext = _concat(enc, pkRm);
135
+ const eaePrk = await _labeledExtract(subtle, _KEM_SUITE_ID, new Uint8Array(0), 'eae_prk', dh);
136
+ const sharedSecret = await _labeledExpand(subtle, _KEM_SUITE_ID, eaePrk, 'shared_secret', kemContext, _N_SECRET);
137
+ return { sharedSecret, enc };
138
+ }
139
+ // RFC 9180 §4.1 DHKEM Decap — deserializes enc, DH with recipient privkey,
140
+ // derives same shared_secret via ExtractAndExpand.
141
+ // Requires recipientPrivateKey to be extractable (JWK export needed for pkRm).
142
+ async function _kemDecap(subtle, enc, recipientPrivateKey) {
143
+ const pkE = await subtle.importKey('raw', _toBufferView(enc), { name: 'X25519' }, true, []);
144
+ const dh = new Uint8Array(await subtle.deriveBits({ name: 'X25519', public: pkE }, recipientPrivateKey, 256));
145
+ // Recover recipient's own public key from JWK x field (base64url-encoded raw X25519 public key).
146
+ const jwk = (await subtle.exportKey('jwk', recipientPrivateKey));
147
+ /* c8 ignore next 3 - defensive: X25519 JWK always has an x field; unreachable via public API */
148
+ if (!jwk.x) {
149
+ throw new Error('HPKE Decap: failed to extract public key bytes from recipient private key JWK');
150
+ }
151
+ const pkRm = _base64UrlDecode(jwk.x);
152
+ const kemContext = _concat(enc, pkRm);
153
+ const eaePrk = await _labeledExtract(subtle, _KEM_SUITE_ID, new Uint8Array(0), 'eae_prk', dh);
154
+ return _labeledExpand(subtle, _KEM_SUITE_ID, eaePrk, 'shared_secret', kemContext, _N_SECRET);
155
+ }
156
+ // RFC 9180 §5 KeySchedule (base mode, psk = b"", psk_id = b"").
157
+ async function _keyScheduleBase(subtle, sharedSecret, info) {
158
+ const empty = new Uint8Array(0);
159
+ const pskIdHash = await _labeledExtract(subtle, _SUITE_ID, empty, 'psk_id_hash', empty);
160
+ const infoHash = await _labeledExtract(subtle, _SUITE_ID, empty, 'info_hash', info);
161
+ const ksContext = _concat(new Uint8Array([_MODE_BASE]), pskIdHash, infoHash);
162
+ const prk = await _labeledExtract(subtle, _SUITE_ID, sharedSecret, 'secret', empty);
163
+ const key = await _labeledExpand(subtle, _SUITE_ID, prk, 'key', ksContext, _N_K);
164
+ const baseNonce = await _labeledExpand(subtle, _SUITE_ID, prk, 'base_nonce', ksContext, _N_N);
165
+ return { key, baseNonce };
166
+ }
167
+ // ---- Public class ----
168
+ /**
169
+ * HPKE base mode (RFC 9180) — `DHKEM(X25519, HKDF-SHA256) + HKDF-SHA256 + AES-256-GCM`.
170
+ *
171
+ * Class-based provider that captures a `SubtleCrypto` instance at construction,
172
+ * matching the existing `NodeCryptoProvider` / `BrowserCryptoProvider` / `KeyStore`
173
+ * factory pattern used throughout `@fgv/ts-extras/crypto-utils`.
174
+ *
175
+ * **Node.js usage:**
176
+ * ```typescript
177
+ * import * as crypto from 'crypto';
178
+ * const hpke = HpkeProvider.create(crypto.webcrypto.subtle).orThrow();
179
+ * ```
180
+ *
181
+ * **Browser usage:**
182
+ * ```typescript
183
+ * const hpke = HpkeProvider.create(globalThis.crypto.subtle).orThrow();
184
+ * ```
185
+ *
186
+ * **Runtime requirements:** Node.js 20+ (X25519 in `crypto.webcrypto`);
187
+ * Chrome 113+, Safari 16.4+, Firefox 118+ (X25519 added to Web Crypto in 2023).
188
+ * @public
189
+ */
190
+ export class HpkeProvider {
191
+ constructor(subtle) {
192
+ this._subtle = subtle;
193
+ }
194
+ /**
195
+ * Creates an `HpkeProvider` bound to the given `SubtleCrypto` instance.
196
+ *
197
+ * @param subtle - Web Crypto SubtleCrypto instance.
198
+ * Node.js: `(await import('crypto')).webcrypto.subtle`.
199
+ * Browser: `globalThis.crypto.subtle`.
200
+ * @returns `Success` with the provider, or `Failure` if construction fails.
201
+ */
202
+ static create(subtle) {
203
+ return captureResult(() => new HpkeProvider(subtle));
204
+ }
205
+ /**
206
+ * HPKE base-mode seal (sender side). RFC 9180 §6.1.
207
+ *
208
+ * Generates a fresh ephemeral X25519 keypair, runs DHKEM Encap to produce a
209
+ * shared secret and `enc` (32-byte raw ephemeral public key), derives the AEAD
210
+ * key and nonce deterministically via the RFC 9180 key schedule, then encrypts
211
+ * `plaintext` with AES-256-GCM.
212
+ *
213
+ * @param recipientPublicKey - Recipient's X25519 public `CryptoKey`
214
+ * (`algorithm.name === 'X25519'`, `type === 'public'`, **`extractable: true`**).
215
+ * Must be extractable — DHKEM Encap calls `exportKey('raw', ...)` on this key to
216
+ * build the KEM shared-secret context. Keys imported with `extractable: false` will
217
+ * cause this method to return a `Failure`.
218
+ * @param info - Context-binding bytes. **Load-bearing — no default.**
219
+ * Binds this ciphertext to a specific application context, preventing replay
220
+ * across different contexts sharing the same recipient keypair.
221
+ * Use `new TextEncoder().encode('myapp/v1/use-case\x00' + contextId)` pattern.
222
+ * Never pass an empty array in production: empty `info` provides no context binding.
223
+ * @param aad - Additional authenticated data. Integrity-protected but not encrypted.
224
+ * `new Uint8Array(0)` is valid when no AAD is needed.
225
+ * @param plaintext - Bytes to encrypt. `new Uint8Array(0)` is valid.
226
+ * @returns `Success` with `{ enc, ciphertext }`, or `Failure` with error context.
227
+ */
228
+ async sealBase(recipientPublicKey, info, aad, plaintext) {
229
+ const result = await captureAsyncResult(async () => {
230
+ const { sharedSecret, enc } = await _kemEncap(this._subtle, recipientPublicKey);
231
+ const { key, baseNonce } = await _keyScheduleBase(this._subtle, sharedSecret, info);
232
+ const aesKey = await this._subtle.importKey('raw', key, { name: 'AES-GCM' }, false, ['encrypt']);
233
+ const ct = await this._subtle.encrypt({ name: 'AES-GCM', iv: baseNonce, additionalData: _toBufferView(aad) }, aesKey, _toBufferView(plaintext));
234
+ return { enc, ciphertext: new Uint8Array(ct) };
235
+ });
236
+ return result.withErrorFormat((e) => `HPKE sealBase failed: ${e}`);
237
+ }
238
+ /**
239
+ * HPKE base-mode open (recipient side). RFC 9180 §6.1.
240
+ *
241
+ * Decapsulates `enc` using the recipient's X25519 private key, derives the same
242
+ * AEAD key and nonce from the shared secret and `info`, then authenticates and
243
+ * decrypts `ciphertext` with AES-256-GCM.
244
+ *
245
+ * Returns `Failure` on any of:
246
+ * - Wrong private key (different DH output → different key derivation)
247
+ * - Wrong `info` (different key schedule context → different AEAD key)
248
+ * - Wrong `aad` (AES-GCM authentication fails)
249
+ * - Tampered `ciphertext` or `enc` (authentication fails or DH fails)
250
+ * - `enc` not exactly 32 bytes
251
+ * - `ciphertext` shorter than 16 bytes (no room for authentication tag)
252
+ *
253
+ * @param recipientPrivateKey - Recipient's X25519 private `CryptoKey`
254
+ * (`algorithm.name === 'X25519'`, `type === 'private'`, `usages` includes `'deriveBits'`).
255
+ * **Must be extractable** (`extractable: true`) — the recipient's public key bytes
256
+ * are recovered from the JWK `x` field during Decap.
257
+ * @param info - Context-binding bytes. Must exactly match `info` from `sealBase`.
258
+ * @param aad - Must exactly match `aad` from `sealBase`.
259
+ * @param enc - The encapsulated key from `sealBase` — exactly 32 bytes.
260
+ * @param ciphertext - The ciphertext from `sealBase` — `plaintext.length + 16` bytes.
261
+ * @returns `Success` with decrypted plaintext bytes, or `Failure` with error context.
262
+ */
263
+ async openBase(recipientPrivateKey, info, aad, enc, ciphertext) {
264
+ if (enc.length !== _N_PK) {
265
+ return fail(`HPKE openBase: enc must be ${_N_PK} bytes, got ${enc.length}`);
266
+ }
267
+ if (ciphertext.length < _N_T) {
268
+ return fail(`HPKE openBase: ciphertext too short (minimum ${_N_T} bytes for auth tag, got ${ciphertext.length})`);
269
+ }
270
+ const result = await captureAsyncResult(async () => {
271
+ const sharedSecret = await _kemDecap(this._subtle, enc, recipientPrivateKey);
272
+ const { key, baseNonce } = await _keyScheduleBase(this._subtle, sharedSecret, info);
273
+ const aesKey = await this._subtle.importKey('raw', key, { name: 'AES-GCM' }, false, ['decrypt']);
274
+ const pt = await this._subtle.decrypt({ name: 'AES-GCM', iv: baseNonce, additionalData: _toBufferView(aad) }, aesKey, _toBufferView(ciphertext));
275
+ return new Uint8Array(pt);
276
+ });
277
+ return result.withErrorFormat((e) => `HPKE openBase failed: ${e}`);
278
+ }
279
+ /**
280
+ * HKDF-SHA256 key derivation (RFC 5869). Extract-then-Expand using SHA-256.
281
+ *
282
+ * This is raw RFC 5869 HKDF — it does **not** use RFC 9180's labeled variants.
283
+ * The HPKE key schedule internally uses labeled HKDF; this method is the unlabeled
284
+ * version for callers that need standalone key derivation.
285
+ *
286
+ * @param secret - Input keying material (IKM). Any length.
287
+ * @param salt - Optional salt. Use `new Uint8Array(0)` if no salt is available
288
+ * (RFC 5869: 32 zero bytes are used internally when salt is empty).
289
+ * @param info - Context / application-binding bytes. Any length.
290
+ * @param length - Number of output bytes to derive. Maximum 8160 bytes (255 × 32).
291
+ * @returns `Success` with derived bytes, or `Failure` with error context.
292
+ */
293
+ async hkdf(secret, salt, info, length) {
294
+ const result = await captureAsyncResult(async () => {
295
+ const prk = await _hkdfExtract(this._subtle, salt, secret);
296
+ return _hkdfExpand(this._subtle, prk, info, length);
297
+ });
298
+ return result.withErrorFormat((e) => `HKDF failed: ${e}`);
299
+ }
300
+ /**
301
+ * Encodes an {@link IHpkeSealResult} as a single contiguous byte array for wire transport.
302
+ *
303
+ * Format: `enc` (32 bytes, fixed) || `ciphertext` (variable length).
304
+ * The 32-byte `enc` length is fixed for X25519; the split point is unambiguous.
305
+ *
306
+ * @param result - The output of {@link HpkeProvider.sealBase}.
307
+ * @returns Concatenated bytes: `enc || ciphertext`.
308
+ */
309
+ static encodeEnvelope(result) {
310
+ return _concat(result.enc, result.ciphertext);
311
+ }
312
+ /**
313
+ * Decodes an envelope produced by {@link HpkeProvider.encodeEnvelope}.
314
+ *
315
+ * Validates that the buffer is at least 48 bytes (32-byte enc + 16-byte minimum
316
+ * ciphertext containing the AES-GCM auth tag; zero-length plaintext is the minimum
317
+ * meaningful case).
318
+ *
319
+ * @param envelope - Envelope bytes from `encodeEnvelope`.
320
+ * @returns `Success` with `{ enc, ciphertext }`, or `Failure` if malformed.
321
+ */
322
+ static decodeEnvelope(envelope) {
323
+ const minLen = _N_PK + _N_T;
324
+ if (envelope.length < minLen) {
325
+ return fail(`HPKE decodeEnvelope: envelope too short (minimum ${minLen} bytes, got ${envelope.length})`);
326
+ }
327
+ return succeed({
328
+ enc: envelope.slice(0, _N_PK),
329
+ ciphertext: envelope.slice(_N_PK)
330
+ });
331
+ }
332
+ }
333
+ //# sourceMappingURL=hpkeProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hpkeProvider.js","sourceRoot":"","sources":["../../../src/packlets/crypto-utils/hpkeProvider.ts"],"names":[],"mappings":"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","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 { Result, captureAsyncResult, captureResult, fail, succeed } from '@fgv/ts-utils';\n\n// ---- Internal constants ----\n\n// \"HPKE-v1\" (7 bytes) — RFC 9180 domain separator prefix\nconst _HPKE_VERSION: Uint8Array<ArrayBuffer> = new Uint8Array([0x48, 0x50, 0x4b, 0x45, 0x2d, 0x76, 0x31]);\n\n// suite_id = \"HPKE\" || I2OSP(KEM_ID=0x0020, 2) || I2OSP(KDF_ID=0x0001, 2) || I2OSP(AEAD_ID=0x0002, 2)\n// Used in key schedule LabeledExtract/LabeledExpand calls.\nconst _SUITE_ID: Uint8Array<ArrayBuffer> = new Uint8Array([\n 0x48, 0x50, 0x4b, 0x45, 0x00, 0x20, 0x00, 0x01, 0x00, 0x02\n]);\n\n// kem_suite_id = \"KEM\" || I2OSP(KEM_ID=0x0020, 2)\n// Used in DHKEM-internal LabeledExtract/LabeledExpand calls.\nconst _KEM_SUITE_ID: Uint8Array<ArrayBuffer> = new Uint8Array([0x4b, 0x45, 0x4d, 0x00, 0x20]);\n\nconst _N_SECRET: number = 32; // Nsecret: KEM shared-secret output length\nconst _N_PK: number = 32; // Npk: X25519 public key (raw) length — also the enc length\nconst _N_K: number = 32; // Nk: AES-256-GCM key length\nconst _N_N: number = 12; // Nn: AES-256-GCM nonce length\nconst _N_T: number = 16; // Nt: AES-256-GCM authentication tag length\nconst _MODE_BASE: number = 0x00; // RFC 9180 mode_base\n\n// ---- Internal helpers ----\n// These are NOT exported. Per design D7, only the five public operations are public surface.\n\n// Copies any Uint8Array into a fresh Uint8Array<ArrayBuffer>.\n// Required to satisfy TypeScript's strict BufferSource typing for Web Crypto API calls —\n// subtle.* rejects Uint8Array<ArrayBufferLike> but accepts Uint8Array<ArrayBuffer>.\n// Pattern follows browserCryptoProvider.ts toBufferView.\nfunction _toBufferView(arr: Uint8Array): Uint8Array<ArrayBuffer> {\n const buffer = new ArrayBuffer(arr.byteLength);\n const view = new Uint8Array(buffer);\n view.set(arr);\n return view;\n}\n\nfunction _concat(...arrays: Uint8Array[]): Uint8Array<ArrayBuffer> {\n const total = arrays.reduce((n, a) => n + a.length, 0);\n const buffer = new ArrayBuffer(total);\n const out = new Uint8Array(buffer);\n let offset = 0;\n for (const a of arrays) {\n out.set(a, offset);\n offset += a.length;\n }\n return out;\n}\n\nfunction _i2osp(value: number, length: number): Uint8Array<ArrayBuffer> {\n const buffer = new ArrayBuffer(length);\n const out = new Uint8Array(buffer);\n for (let i = length - 1; i >= 0; i--) {\n out[i] = value % 256;\n value = Math.floor(value / 256);\n }\n return out;\n}\n\n// Decodes a base64url-encoded string to Uint8Array<ArrayBuffer>.\n// Uses `atob` (global in Node 18+ and all modern browsers; no import needed).\nfunction _base64UrlDecode(s: string): Uint8Array<ArrayBuffer> {\n const base64 = s.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);\n const binary = atob(padded);\n const buffer = new ArrayBuffer(binary.length);\n const out = new Uint8Array(buffer);\n for (let i = 0; i < binary.length; i++) {\n out[i] = binary.charCodeAt(i);\n }\n return out;\n}\n\n// HMAC-SHA256(key, data) — the underlying primitive for HKDF.\nasync function _hmacSha256(\n subtle: SubtleCrypto,\n key: Uint8Array,\n data: Uint8Array\n): Promise<Uint8Array<ArrayBuffer>> {\n const hmacKey = await subtle.importKey(\n 'raw',\n _toBufferView(key),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign']\n );\n return new Uint8Array(await subtle.sign('HMAC', hmacKey, _toBufferView(data)));\n}\n\n// RFC 5869 HKDF-Extract(salt, IKM) = HMAC-SHA256(key=salt, msg=IKM).\n// If salt is empty (length 0), uses 32 zero bytes per RFC 5869 §2.2.\nasync function _hkdfExtract(\n subtle: SubtleCrypto,\n salt: Uint8Array,\n ikm: Uint8Array\n): Promise<Uint8Array<ArrayBuffer>> {\n const effectiveSalt = salt.length === 0 ? new Uint8Array(32) : salt;\n return _hmacSha256(subtle, effectiveSalt, ikm);\n}\n\n// RFC 5869 HKDF-Expand(PRK, info, L) — iterative HMAC expansion.\nasync function _hkdfExpand(\n subtle: SubtleCrypto,\n prk: Uint8Array,\n info: Uint8Array,\n length: number\n): Promise<Uint8Array<ArrayBuffer>> {\n if (length > 255 * 32) {\n throw new Error(`HKDF-Expand: requested length ${length} exceeds maximum 8160 bytes (255 * HashLen)`);\n }\n const n = Math.ceil(length / 32);\n const buffer = new ArrayBuffer(length);\n const okm = new Uint8Array(buffer);\n let prev: Uint8Array<ArrayBuffer> = new Uint8Array(new ArrayBuffer(0));\n let offset = 0;\n for (let i = 1; i <= n; i++) {\n prev = await _hmacSha256(subtle, prk, _concat(prev, info, new Uint8Array([i])));\n const toCopy = Math.min(32, length - offset);\n okm.set(prev.subarray(0, toCopy), offset);\n offset += toCopy;\n }\n return okm;\n}\n\n// RFC 9180 §4 LabeledExtract — HKDF-Extract with HPKE-v1 domain label.\n// labeled_ikm = \"HPKE-v1\" || suite_id || label || ikm\n// Extract(salt, labeled_ikm)\nasync function _labeledExtract(\n subtle: SubtleCrypto,\n suiteId: Uint8Array,\n salt: Uint8Array,\n label: string,\n ikm: Uint8Array\n): Promise<Uint8Array<ArrayBuffer>> {\n const labeledIkm = _concat(_HPKE_VERSION, suiteId, new TextEncoder().encode(label), ikm);\n return _hkdfExtract(subtle, salt, labeledIkm);\n}\n\n// RFC 9180 §4 LabeledExpand — HKDF-Expand with HPKE-v1 domain label.\n// labeled_info = I2OSP(L, 2) || \"HPKE-v1\" || suite_id || label || info\n// Expand(prk, labeled_info, L)\nasync function _labeledExpand(\n subtle: SubtleCrypto,\n suiteId: Uint8Array,\n prk: Uint8Array,\n label: string,\n info: Uint8Array,\n length: number\n): Promise<Uint8Array<ArrayBuffer>> {\n const labeledInfo = _concat(\n _i2osp(length, 2),\n _HPKE_VERSION,\n suiteId,\n new TextEncoder().encode(label),\n info\n );\n return _hkdfExpand(subtle, prk, labeledInfo, length);\n}\n\n// RFC 9180 §4.1 DHKEM Encap — generates ephemeral keypair, DH with recipient pubkey,\n// derives shared_secret via ExtractAndExpand.\n// NOTE: uses label \"eae_prk\" (not \"dh\") per RFC 9180 §4.1 ExtractAndExpand.\nasync function _kemEncap(\n subtle: SubtleCrypto,\n recipientPublicKey: CryptoKey\n): Promise<{ sharedSecret: Uint8Array<ArrayBuffer>; enc: Uint8Array<ArrayBuffer> }> {\n const ephemeral = (await subtle.generateKey({ name: 'X25519' }, true, ['deriveBits'])) as CryptoKeyPair;\n const enc = new Uint8Array(await subtle.exportKey('raw', ephemeral.publicKey));\n const dh = new Uint8Array(\n await subtle.deriveBits({ name: 'X25519', public: recipientPublicKey }, ephemeral.privateKey, 256)\n );\n const pkRm = new Uint8Array(await subtle.exportKey('raw', recipientPublicKey));\n const kemContext = _concat(enc, pkRm);\n const eaePrk = await _labeledExtract(subtle, _KEM_SUITE_ID, new Uint8Array(0), 'eae_prk', dh);\n const sharedSecret = await _labeledExpand(\n subtle,\n _KEM_SUITE_ID,\n eaePrk,\n 'shared_secret',\n kemContext,\n _N_SECRET\n );\n return { sharedSecret, enc };\n}\n\n// RFC 9180 §4.1 DHKEM Decap — deserializes enc, DH with recipient privkey,\n// derives same shared_secret via ExtractAndExpand.\n// Requires recipientPrivateKey to be extractable (JWK export needed for pkRm).\nasync function _kemDecap(\n subtle: SubtleCrypto,\n enc: Uint8Array,\n recipientPrivateKey: CryptoKey\n): Promise<Uint8Array<ArrayBuffer>> {\n const pkE = await subtle.importKey('raw', _toBufferView(enc), { name: 'X25519' }, true, []);\n const dh = new Uint8Array(\n await subtle.deriveBits({ name: 'X25519', public: pkE }, recipientPrivateKey, 256)\n );\n // Recover recipient's own public key from JWK x field (base64url-encoded raw X25519 public key).\n const jwk = (await subtle.exportKey('jwk', recipientPrivateKey)) as JsonWebKey;\n /* c8 ignore next 3 - defensive: X25519 JWK always has an x field; unreachable via public API */\n if (!jwk.x) {\n throw new Error('HPKE Decap: failed to extract public key bytes from recipient private key JWK');\n }\n const pkRm = _base64UrlDecode(jwk.x);\n const kemContext = _concat(enc, pkRm);\n const eaePrk = await _labeledExtract(subtle, _KEM_SUITE_ID, new Uint8Array(0), 'eae_prk', dh);\n return _labeledExpand(subtle, _KEM_SUITE_ID, eaePrk, 'shared_secret', kemContext, _N_SECRET);\n}\n\n// RFC 9180 §5 KeySchedule (base mode, psk = b\"\", psk_id = b\"\").\nasync function _keyScheduleBase(\n subtle: SubtleCrypto,\n sharedSecret: Uint8Array,\n info: Uint8Array\n): Promise<{ key: Uint8Array<ArrayBuffer>; baseNonce: Uint8Array<ArrayBuffer> }> {\n const empty = new Uint8Array(0);\n const pskIdHash = await _labeledExtract(subtle, _SUITE_ID, empty, 'psk_id_hash', empty);\n const infoHash = await _labeledExtract(subtle, _SUITE_ID, empty, 'info_hash', info);\n const ksContext = _concat(new Uint8Array([_MODE_BASE]), pskIdHash, infoHash);\n const prk = await _labeledExtract(subtle, _SUITE_ID, sharedSecret, 'secret', empty);\n const key = await _labeledExpand(subtle, _SUITE_ID, prk, 'key', ksContext, _N_K);\n const baseNonce = await _labeledExpand(subtle, _SUITE_ID, prk, 'base_nonce', ksContext, _N_N);\n return { key, baseNonce };\n}\n\n// ---- Public types ----\n\n/**\n * Output of {@link HpkeProvider.sealBase}.\n *\n * The `ciphertext` field includes the 16-byte AES-256-GCM authentication tag\n * appended by Web Crypto's `encrypt()` operation: `length = plaintext.length + 16`.\n * @public\n */\nexport interface IHpkeSealResult {\n /**\n * Encapsulated key — 32-byte raw X25519 ephemeral public key (`enc` in RFC 9180).\n * Must be transmitted to the recipient alongside `ciphertext`.\n */\n readonly enc: Uint8Array;\n\n /**\n * AES-256-GCM ciphertext with the 16-byte authentication tag appended.\n * Length = `plaintext.length + 16`.\n */\n readonly ciphertext: Uint8Array;\n}\n\n// ---- Public class ----\n\n/**\n * HPKE base mode (RFC 9180) — `DHKEM(X25519, HKDF-SHA256) + HKDF-SHA256 + AES-256-GCM`.\n *\n * Class-based provider that captures a `SubtleCrypto` instance at construction,\n * matching the existing `NodeCryptoProvider` / `BrowserCryptoProvider` / `KeyStore`\n * factory pattern used throughout `@fgv/ts-extras/crypto-utils`.\n *\n * **Node.js usage:**\n * ```typescript\n * import * as crypto from 'crypto';\n * const hpke = HpkeProvider.create(crypto.webcrypto.subtle).orThrow();\n * ```\n *\n * **Browser usage:**\n * ```typescript\n * const hpke = HpkeProvider.create(globalThis.crypto.subtle).orThrow();\n * ```\n *\n * **Runtime requirements:** Node.js 20+ (X25519 in `crypto.webcrypto`);\n * Chrome 113+, Safari 16.4+, Firefox 118+ (X25519 added to Web Crypto in 2023).\n * @public\n */\nexport class HpkeProvider {\n private readonly _subtle: SubtleCrypto;\n\n private constructor(subtle: SubtleCrypto) {\n this._subtle = subtle;\n }\n\n /**\n * Creates an `HpkeProvider` bound to the given `SubtleCrypto` instance.\n *\n * @param subtle - Web Crypto SubtleCrypto instance.\n * Node.js: `(await import('crypto')).webcrypto.subtle`.\n * Browser: `globalThis.crypto.subtle`.\n * @returns `Success` with the provider, or `Failure` if construction fails.\n */\n public static create(subtle: SubtleCrypto): Result<HpkeProvider> {\n return captureResult(() => new HpkeProvider(subtle));\n }\n\n /**\n * HPKE base-mode seal (sender side). RFC 9180 §6.1.\n *\n * Generates a fresh ephemeral X25519 keypair, runs DHKEM Encap to produce a\n * shared secret and `enc` (32-byte raw ephemeral public key), derives the AEAD\n * key and nonce deterministically via the RFC 9180 key schedule, then encrypts\n * `plaintext` with AES-256-GCM.\n *\n * @param recipientPublicKey - Recipient's X25519 public `CryptoKey`\n * (`algorithm.name === 'X25519'`, `type === 'public'`, **`extractable: true`**).\n * Must be extractable — DHKEM Encap calls `exportKey('raw', ...)` on this key to\n * build the KEM shared-secret context. Keys imported with `extractable: false` will\n * cause this method to return a `Failure`.\n * @param info - Context-binding bytes. **Load-bearing — no default.**\n * Binds this ciphertext to a specific application context, preventing replay\n * across different contexts sharing the same recipient keypair.\n * Use `new TextEncoder().encode('myapp/v1/use-case\\x00' + contextId)` pattern.\n * Never pass an empty array in production: empty `info` provides no context binding.\n * @param aad - Additional authenticated data. Integrity-protected but not encrypted.\n * `new Uint8Array(0)` is valid when no AAD is needed.\n * @param plaintext - Bytes to encrypt. `new Uint8Array(0)` is valid.\n * @returns `Success` with `{ enc, ciphertext }`, or `Failure` with error context.\n */\n public async sealBase(\n recipientPublicKey: CryptoKey,\n info: Uint8Array,\n aad: Uint8Array,\n plaintext: Uint8Array\n ): Promise<Result<IHpkeSealResult>> {\n const result = await captureAsyncResult(async () => {\n const { sharedSecret, enc } = await _kemEncap(this._subtle, recipientPublicKey);\n const { key, baseNonce } = await _keyScheduleBase(this._subtle, sharedSecret, info);\n const aesKey = await this._subtle.importKey('raw', key, { name: 'AES-GCM' }, false, ['encrypt']);\n const ct = await this._subtle.encrypt(\n { name: 'AES-GCM', iv: baseNonce, additionalData: _toBufferView(aad) },\n aesKey,\n _toBufferView(plaintext)\n );\n return { enc, ciphertext: new Uint8Array(ct) };\n });\n return result.withErrorFormat((e: string) => `HPKE sealBase failed: ${e}`);\n }\n\n /**\n * HPKE base-mode open (recipient side). RFC 9180 §6.1.\n *\n * Decapsulates `enc` using the recipient's X25519 private key, derives the same\n * AEAD key and nonce from the shared secret and `info`, then authenticates and\n * decrypts `ciphertext` with AES-256-GCM.\n *\n * Returns `Failure` on any of:\n * - Wrong private key (different DH output → different key derivation)\n * - Wrong `info` (different key schedule context → different AEAD key)\n * - Wrong `aad` (AES-GCM authentication fails)\n * - Tampered `ciphertext` or `enc` (authentication fails or DH fails)\n * - `enc` not exactly 32 bytes\n * - `ciphertext` shorter than 16 bytes (no room for authentication tag)\n *\n * @param recipientPrivateKey - Recipient's X25519 private `CryptoKey`\n * (`algorithm.name === 'X25519'`, `type === 'private'`, `usages` includes `'deriveBits'`).\n * **Must be extractable** (`extractable: true`) — the recipient's public key bytes\n * are recovered from the JWK `x` field during Decap.\n * @param info - Context-binding bytes. Must exactly match `info` from `sealBase`.\n * @param aad - Must exactly match `aad` from `sealBase`.\n * @param enc - The encapsulated key from `sealBase` — exactly 32 bytes.\n * @param ciphertext - The ciphertext from `sealBase` — `plaintext.length + 16` bytes.\n * @returns `Success` with decrypted plaintext bytes, or `Failure` with error context.\n */\n public async openBase(\n recipientPrivateKey: CryptoKey,\n info: Uint8Array,\n aad: Uint8Array,\n enc: Uint8Array,\n ciphertext: Uint8Array\n ): Promise<Result<Uint8Array>> {\n if (enc.length !== _N_PK) {\n return fail(`HPKE openBase: enc must be ${_N_PK} bytes, got ${enc.length}`);\n }\n if (ciphertext.length < _N_T) {\n return fail(\n `HPKE openBase: ciphertext too short (minimum ${_N_T} bytes for auth tag, got ${ciphertext.length})`\n );\n }\n const result = await captureAsyncResult(async () => {\n const sharedSecret = await _kemDecap(this._subtle, enc, recipientPrivateKey);\n const { key, baseNonce } = await _keyScheduleBase(this._subtle, sharedSecret, info);\n const aesKey = await this._subtle.importKey('raw', key, { name: 'AES-GCM' }, false, ['decrypt']);\n const pt = await this._subtle.decrypt(\n { name: 'AES-GCM', iv: baseNonce, additionalData: _toBufferView(aad) },\n aesKey,\n _toBufferView(ciphertext)\n );\n return new Uint8Array(pt);\n });\n return result.withErrorFormat((e: string) => `HPKE openBase failed: ${e}`);\n }\n\n /**\n * HKDF-SHA256 key derivation (RFC 5869). Extract-then-Expand using SHA-256.\n *\n * This is raw RFC 5869 HKDF — it does **not** use RFC 9180's labeled variants.\n * The HPKE key schedule internally uses labeled HKDF; this method is the unlabeled\n * version for callers that need standalone key derivation.\n *\n * @param secret - Input keying material (IKM). Any length.\n * @param salt - Optional salt. Use `new Uint8Array(0)` if no salt is available\n * (RFC 5869: 32 zero bytes are used internally when salt is empty).\n * @param info - Context / application-binding bytes. Any length.\n * @param length - Number of output bytes to derive. Maximum 8160 bytes (255 × 32).\n * @returns `Success` with derived bytes, or `Failure` with error context.\n */\n public async hkdf(\n secret: Uint8Array,\n salt: Uint8Array,\n info: Uint8Array,\n length: number\n ): Promise<Result<Uint8Array>> {\n const result = await captureAsyncResult(async () => {\n const prk = await _hkdfExtract(this._subtle, salt, secret);\n return _hkdfExpand(this._subtle, prk, info, length);\n });\n return result.withErrorFormat((e: string) => `HKDF failed: ${e}`);\n }\n\n /**\n * Encodes an {@link IHpkeSealResult} as a single contiguous byte array for wire transport.\n *\n * Format: `enc` (32 bytes, fixed) || `ciphertext` (variable length).\n * The 32-byte `enc` length is fixed for X25519; the split point is unambiguous.\n *\n * @param result - The output of {@link HpkeProvider.sealBase}.\n * @returns Concatenated bytes: `enc || ciphertext`.\n */\n public static encodeEnvelope(result: IHpkeSealResult): Uint8Array {\n return _concat(result.enc, result.ciphertext);\n }\n\n /**\n * Decodes an envelope produced by {@link HpkeProvider.encodeEnvelope}.\n *\n * Validates that the buffer is at least 48 bytes (32-byte enc + 16-byte minimum\n * ciphertext containing the AES-GCM auth tag; zero-length plaintext is the minimum\n * meaningful case).\n *\n * @param envelope - Envelope bytes from `encodeEnvelope`.\n * @returns `Success` with `{ enc, ciphertext }`, or `Failure` if malformed.\n */\n public static decodeEnvelope(envelope: Uint8Array): Result<IHpkeSealResult> {\n const minLen = _N_PK + _N_T;\n if (envelope.length < minLen) {\n return fail(\n `HPKE decodeEnvelope: envelope too short (minimum ${minLen} bytes, got ${envelope.length})`\n );\n }\n return succeed({\n enc: envelope.slice(0, _N_PK),\n ciphertext: envelope.slice(_N_PK)\n });\n }\n}\n"]}
@@ -34,8 +34,15 @@ import * as Converters from './converters';
34
34
  export { Converters };
35
35
  // Direct encryption provider
36
36
  export { DirectEncryptionProvider } from './directEncryptionProvider';
37
+ // WebCrypto parameter table for asymmetric keypair algorithms
38
+ export { keyPairAlgorithmParams } from './keyPairAlgorithmParams';
37
39
  // Note: NodeCryptoProvider is NOT exported in browser version
38
40
  // Use BrowserCryptoProvider from @fgv/ts-web-extras instead
39
41
  // Encrypted file helpers
40
42
  export { createEncryptedFile, decryptFile, fromBase64, toBase64, tryDecryptFile } from './encryptedFile';
43
+ // Multibase/SPKI helpers
44
+ export { exportPublicKeyAsMultibaseSpki, importPublicKeyFromMultibaseSpki, multibaseBase64UrlDecode, multibaseBase64UrlEncode } from './spkiHelpers';
45
+ // HPKE base mode (RFC 9180) — DHKEM(X25519, HKDF-SHA256) + HKDF-SHA256 + AES-256-GCM
46
+ // hpkeProvider.ts has no Node-specific imports and is safe in the browser entry point.
47
+ export { HpkeProvider } from './hpkeProvider';
41
48
  //# sourceMappingURL=index.browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.browser.js","sourceRoot":"","sources":["../../../src/packlets/crypto-utils/index.browser.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,iCAAiC;AACjC,cAAc,SAAS,CAAC;AAExB,YAAY;AACZ,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EACjB,WAAW,EACZ,MAAM,aAAa,CAAC;AAErB,qBAAqB;AACrB,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,CAAC;AAEpB,uBAAuB;AACvB,OAAO,KAAK,UAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,6BAA6B;AAC7B,OAAO,EAAE,wBAAwB,EAAmC,MAAM,4BAA4B,CAAC;AAEvG,8DAA8D;AAC9D,OAAO,EAA2B,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAE3F,8DAA8D;AAC9D,4DAA4D;AAE5D,yBAAyB;AACzB,OAAO,EACL,mBAAmB,EACnB,WAAW,EACX,UAAU,EAEV,QAAQ,EACR,cAAc,EACf,MAAM,iBAAiB,CAAC;AAEzB,yBAAyB;AACzB,OAAO,EACL,8BAA8B,EAC9B,gCAAgC,EAChC,wBAAwB,EACxB,wBAAwB,EACzB,MAAM,eAAe,CAAC;AAEvB,qFAAqF;AACrF,uFAAuF;AACvF,OAAO,EAAE,YAAY,EAAmB,MAAM,gBAAgB,CAAC","sourcesContent":["// Copyright (c) 2024 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 * Crypto utilities for encrypted file handling and key management (browser version).\n * Note: For browser crypto provider, use \\@fgv/ts-web-extras.\n * @packageDocumentation\n */\n\n// Re-export all types from model\nexport * from './model';\n\n// Constants\nexport {\n AES_256_KEY_SIZE,\n DEFAULT_ALGORITHM,\n ENCRYPTED_FILE_FORMAT,\n GCM_AUTH_TAG_SIZE,\n GCM_IV_SIZE\n} from './constants';\n\n// KeyStore namespace\nimport * as KeyStore from './keystore';\nexport { KeyStore };\n\n// Converters namespace\nimport * as Converters from './converters';\nexport { Converters };\n\n// Direct encryption provider\nexport { DirectEncryptionProvider, IDirectEncryptionProviderParams } from './directEncryptionProvider';\n\n// WebCrypto parameter table for asymmetric keypair algorithms\nexport { IKeyPairAlgorithmParams, keyPairAlgorithmParams } from './keyPairAlgorithmParams';\n\n// Note: NodeCryptoProvider is NOT exported in browser version\n// Use BrowserCryptoProvider from @fgv/ts-web-extras instead\n\n// Encrypted file helpers\nexport {\n createEncryptedFile,\n decryptFile,\n fromBase64,\n ICreateEncryptedFileParams,\n toBase64,\n tryDecryptFile\n} from './encryptedFile';\n\n// Multibase/SPKI helpers\nexport {\n exportPublicKeyAsMultibaseSpki,\n importPublicKeyFromMultibaseSpki,\n multibaseBase64UrlDecode,\n multibaseBase64UrlEncode\n} from './spkiHelpers';\n\n// HPKE base mode (RFC 9180) — DHKEM(X25519, HKDF-SHA256) + HKDF-SHA256 + AES-256-GCM\n// hpkeProvider.ts has no Node-specific imports and is safe in the browser entry point.\nexport { HpkeProvider, IHpkeSealResult } from './hpkeProvider';\n"]}
@@ -34,8 +34,14 @@ import * as Converters from './converters';
34
34
  export { Converters };
35
35
  // Direct encryption provider
36
36
  export { DirectEncryptionProvider } from './directEncryptionProvider';
37
+ // WebCrypto parameter table for asymmetric keypair algorithms
38
+ export { keyPairAlgorithmParams } from './keyPairAlgorithmParams';
37
39
  // Node.js crypto provider (Node.js environment only)
38
40
  export { NodeCryptoProvider, nodeCryptoProvider } from './nodeCryptoProvider';
39
41
  // Encrypted file helpers
40
42
  export { createEncryptedFile, decryptFile, fromBase64, toBase64, tryDecryptFile } from './encryptedFile';
43
+ // Multibase/SPKI helpers
44
+ export { exportPublicKeyAsMultibaseSpki, importPublicKeyFromMultibaseSpki, multibaseBase64UrlDecode, multibaseBase64UrlEncode } from './spkiHelpers';
45
+ // HPKE base mode (RFC 9180) — DHKEM(X25519, HKDF-SHA256) + HKDF-SHA256 + AES-256-GCM
46
+ export { HpkeProvider } from './hpkeProvider';
41
47
  //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/crypto-utils/index.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;;;GAGG;AAEH,iCAAiC;AACjC,cAAc,SAAS,CAAC;AAExB,YAAY;AACZ,OAAO,KAAK,SAAS,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,qBAAqB;AACrB,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,CAAC;AAEpB,uBAAuB;AACvB,OAAO,KAAK,UAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,6BAA6B;AAC7B,OAAO,EAAE,wBAAwB,EAAmC,MAAM,4BAA4B,CAAC;AAEvG,8DAA8D;AAC9D,OAAO,EAA2B,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAE3F,qDAAqD;AACrD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE9E,yBAAyB;AACzB,OAAO,EACL,mBAAmB,EACnB,WAAW,EACX,UAAU,EAEV,QAAQ,EACR,cAAc,EACf,MAAM,iBAAiB,CAAC;AAEzB,yBAAyB;AACzB,OAAO,EACL,8BAA8B,EAC9B,gCAAgC,EAChC,wBAAwB,EACxB,wBAAwB,EACzB,MAAM,eAAe,CAAC;AAEvB,qFAAqF;AACrF,OAAO,EAAE,YAAY,EAAmB,MAAM,gBAAgB,CAAC","sourcesContent":["// Copyright (c) 2024 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 * Crypto utilities for encrypted file handling and key management.\n * @packageDocumentation\n */\n\n// Re-export all types from model\nexport * from './model';\n\n// Constants\nimport * as Constants from './constants';\nexport { Constants };\n\n// KeyStore namespace\nimport * as KeyStore from './keystore';\nexport { KeyStore };\n\n// Converters namespace\nimport * as Converters from './converters';\nexport { Converters };\n\n// Direct encryption provider\nexport { DirectEncryptionProvider, IDirectEncryptionProviderParams } from './directEncryptionProvider';\n\n// WebCrypto parameter table for asymmetric keypair algorithms\nexport { IKeyPairAlgorithmParams, keyPairAlgorithmParams } from './keyPairAlgorithmParams';\n\n// Node.js crypto provider (Node.js environment only)\nexport { NodeCryptoProvider, nodeCryptoProvider } from './nodeCryptoProvider';\n\n// Encrypted file helpers\nexport {\n createEncryptedFile,\n decryptFile,\n fromBase64,\n ICreateEncryptedFileParams,\n toBase64,\n tryDecryptFile\n} from './encryptedFile';\n\n// Multibase/SPKI helpers\nexport {\n exportPublicKeyAsMultibaseSpki,\n importPublicKeyFromMultibaseSpki,\n multibaseBase64UrlDecode,\n multibaseBase64UrlEncode\n} from './spkiHelpers';\n\n// HPKE base mode (RFC 9180) — DHKEM(X25519, HKDF-SHA256) + HKDF-SHA256 + AES-256-GCM\nexport { HpkeProvider, IHpkeSealResult } from './hpkeProvider';\n"]}
@@ -0,0 +1,71 @@
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
+ * Lookup table from {@link CryptoUtils.KeyPairAlgorithm} to the WebCrypto
22
+ * parameters needed to drive `crypto.subtle`. Shared between every
23
+ * {@link CryptoUtils.ICryptoProvider} implementation since both Node and
24
+ * browser providers speak the same WebCrypto API. Exposed for downstream
25
+ * provider implementations (e.g. browser-side providers in `@fgv/ts-web-extras`).
26
+ * @public
27
+ */
28
+ export const keyPairAlgorithmParams = {
29
+ 'ecdsa-p256': {
30
+ generateKey: { name: 'ECDSA', namedCurve: 'P-256' },
31
+ importPublicKey: { name: 'ECDSA', namedCurve: 'P-256' },
32
+ keyPairUsages: ['sign', 'verify'],
33
+ publicKeyUsages: ['verify']
34
+ },
35
+ 'rsa-oaep-2048': {
36
+ generateKey: {
37
+ name: 'RSA-OAEP',
38
+ modulusLength: 2048,
39
+ publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
40
+ hash: 'SHA-256'
41
+ },
42
+ importPublicKey: { name: 'RSA-OAEP', hash: 'SHA-256' },
43
+ keyPairUsages: ['encrypt', 'decrypt'],
44
+ publicKeyUsages: ['encrypt']
45
+ },
46
+ 'ecdh-p256': {
47
+ generateKey: { name: 'ECDH', namedCurve: 'P-256' },
48
+ importPublicKey: { name: 'ECDH', namedCurve: 'P-256' },
49
+ // WebCrypto filters per-role: the private key takes both derive usages,
50
+ // and the public key gets [] since an ECDH public key alone cannot derive.
51
+ keyPairUsages: ['deriveKey', 'deriveBits'],
52
+ // Importing only the recipient's public key — empty usages because a
53
+ // standalone ECDH public key has no derivation capability.
54
+ publicKeyUsages: []
55
+ },
56
+ ed25519: {
57
+ generateKey: { name: 'Ed25519' },
58
+ importPublicKey: { name: 'Ed25519' },
59
+ keyPairUsages: ['sign', 'verify'],
60
+ publicKeyUsages: ['verify']
61
+ },
62
+ x25519: {
63
+ generateKey: { name: 'X25519' },
64
+ importPublicKey: { name: 'X25519' },
65
+ // WebCrypto filters per-role: the private key takes both derive usages,
66
+ // the public key gets [] since a standalone X25519 public key cannot derive.
67
+ keyPairUsages: ['deriveKey', 'deriveBits'],
68
+ publicKeyUsages: []
69
+ }
70
+ };
71
+ //# sourceMappingURL=keyPairAlgorithmParams.js.map