@aglyn/shared-util-tools 1.0.0-beta.143

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 (288) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +7 -0
  3. package/package.json +39 -0
  4. package/src/index.d.ts +72 -0
  5. package/src/index.js +87 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/apply-mixins.d.ts +24 -0
  8. package/src/lib/apply-mixins.js +31 -0
  9. package/src/lib/apply-mixins.js.map +1 -0
  10. package/src/lib/array/array-copy-deep.d.ts +6 -0
  11. package/src/lib/array/array-copy-deep.js +25 -0
  12. package/src/lib/array/array-copy-deep.js.map +1 -0
  13. package/src/lib/array/array-copy-shallow.d.ts +19 -0
  14. package/src/lib/array/array-copy-shallow.js +20 -0
  15. package/src/lib/array/array-copy-shallow.js.map +1 -0
  16. package/src/lib/array/array-from-length.d.ts +18 -0
  17. package/src/lib/array/array-from-length.js +23 -0
  18. package/src/lib/array/array-from-length.js.map +1 -0
  19. package/src/lib/array/array-from.d.ts +24 -0
  20. package/src/lib/array/array-from.js +26 -0
  21. package/src/lib/array/array-from.js.map +1 -0
  22. package/src/lib/array/array-move-at-index.d.ts +24 -0
  23. package/src/lib/array/array-move-at-index.js +32 -0
  24. package/src/lib/array/array-move-at-index.js.map +1 -0
  25. package/src/lib/array/array-of-entries-to-object.d.ts +23 -0
  26. package/src/lib/array/array-of-entries-to-object.js +26 -0
  27. package/src/lib/array/array-of-entries-to-object.js.map +1 -0
  28. package/src/lib/array/array-overrides.d.ts +29 -0
  29. package/src/lib/array/array-overrides.js +71 -0
  30. package/src/lib/array/array-overrides.js.map +1 -0
  31. package/src/lib/array/array-push-at-index.d.ts +28 -0
  32. package/src/lib/array/array-push-at-index.js +32 -0
  33. package/src/lib/array/array-push-at-index.js.map +1 -0
  34. package/src/lib/array/array-remove-at-index.d.ts +23 -0
  35. package/src/lib/array/array-remove-at-index.js +26 -0
  36. package/src/lib/array/array-remove-at-index.js.map +1 -0
  37. package/src/lib/array/array-remove-item.d.ts +23 -0
  38. package/src/lib/array/array-remove-item.js +27 -0
  39. package/src/lib/array/array-remove-item.js.map +1 -0
  40. package/src/lib/array/array-safe.d.ts +21 -0
  41. package/src/lib/array/array-safe.js +29 -0
  42. package/src/lib/array/array-safe.js.map +1 -0
  43. package/src/lib/array/array-sort-by-deep-property.d.ts +26 -0
  44. package/src/lib/array/array-sort-by-deep-property.js +39 -0
  45. package/src/lib/array/array-sort-by-deep-property.js.map +1 -0
  46. package/src/lib/array/array-sort-by.d.ts +26 -0
  47. package/src/lib/array/array-sort-by.js +36 -0
  48. package/src/lib/array/array-sort-by.js.map +1 -0
  49. package/src/lib/array/array-update-at-index.d.ts +18 -0
  50. package/src/lib/array/array-update-at-index.js +22 -0
  51. package/src/lib/array/array-update-at-index.js.map +1 -0
  52. package/src/lib/array/array-update.d.ts +23 -0
  53. package/src/lib/array/array-update.js +25 -0
  54. package/src/lib/array/array-update.js.map +1 -0
  55. package/src/lib/bitwise/bitwise-has-all-attributes.d.ts +18 -0
  56. package/src/lib/bitwise/bitwise-has-all-attributes.js +21 -0
  57. package/src/lib/bitwise/bitwise-has-all-attributes.js.map +1 -0
  58. package/src/lib/bitwise/bitwise-has-attribute.d.ts +18 -0
  59. package/src/lib/bitwise/bitwise-has-attribute.js +21 -0
  60. package/src/lib/bitwise/bitwise-has-attribute.js.map +1 -0
  61. package/src/lib/bitwise/bitwise-has-only-attributes.d.ts +18 -0
  62. package/src/lib/bitwise/bitwise-has-only-attributes.js +21 -0
  63. package/src/lib/bitwise/bitwise-has-only-attributes.js.map +1 -0
  64. package/src/lib/contrast.d.ts +65 -0
  65. package/src/lib/contrast.js +78 -0
  66. package/src/lib/contrast.js.map +1 -0
  67. package/src/lib/copy-shallow.d.ts +19 -0
  68. package/src/lib/copy-shallow.js +20 -0
  69. package/src/lib/copy-shallow.js.map +1 -0
  70. package/src/lib/copy.d.ts +19 -0
  71. package/src/lib/copy.js +20 -0
  72. package/src/lib/copy.js.map +1 -0
  73. package/src/lib/create-chained-function.d.ts +38 -0
  74. package/src/lib/create-chained-function.js +46 -0
  75. package/src/lib/create-chained-function.js.map +1 -0
  76. package/src/lib/crud.d.ts +46 -0
  77. package/src/lib/crud.js +55 -0
  78. package/src/lib/crud.js.map +1 -0
  79. package/src/lib/css.d.ts +41 -0
  80. package/src/lib/css.js +54 -0
  81. package/src/lib/css.js.map +1 -0
  82. package/src/lib/escape-html.d.ts +38 -0
  83. package/src/lib/escape-html.js +47 -0
  84. package/src/lib/escape-html.js.map +1 -0
  85. package/src/lib/falsy.d.ts +23 -0
  86. package/src/lib/falsy.js +25 -0
  87. package/src/lib/falsy.js.map +1 -0
  88. package/src/lib/get-display-name.d.ts +46 -0
  89. package/src/lib/get-display-name.js +64 -0
  90. package/src/lib/get-display-name.js.map +1 -0
  91. package/src/lib/get-property.d.ts +30 -0
  92. package/src/lib/get-property.js +36 -0
  93. package/src/lib/get-property.js.map +1 -0
  94. package/src/lib/get-static-field.d.ts +23 -0
  95. package/src/lib/get-static-field.js +25 -0
  96. package/src/lib/get-static-field.js.map +1 -0
  97. package/src/lib/guards/index.d.ts +46 -0
  98. package/src/lib/guards/index.js +47 -0
  99. package/src/lib/guards/index.js.map +1 -0
  100. package/src/lib/guards/lib/_has-own-property.d.ts +24 -0
  101. package/src/lib/guards/lib/_has-own-property.js +27 -0
  102. package/src/lib/guards/lib/_has-own-property.js.map +1 -0
  103. package/src/lib/guards/lib/_is-arr-empty.d.ts +23 -0
  104. package/src/lib/guards/lib/_is-arr-empty.js +25 -0
  105. package/src/lib/guards/lib/_is-arr-empty.js.map +1 -0
  106. package/src/lib/guards/lib/_is-arr-of-arr.d.ts +25 -0
  107. package/src/lib/guards/lib/_is-arr-of-arr.js +31 -0
  108. package/src/lib/guards/lib/_is-arr-of-arr.js.map +1 -0
  109. package/src/lib/guards/lib/_is-arr.d.ts +21 -0
  110. package/src/lib/guards/lib/_is-arr.js +23 -0
  111. package/src/lib/guards/lib/_is-arr.js.map +1 -0
  112. package/src/lib/guards/lib/_is-big.d.ts +25 -0
  113. package/src/lib/guards/lib/_is-big.js +27 -0
  114. package/src/lib/guards/lib/_is-big.js.map +1 -0
  115. package/src/lib/guards/lib/_is-bool.d.ts +25 -0
  116. package/src/lib/guards/lib/_is-bool.js +27 -0
  117. package/src/lib/guards/lib/_is-bool.js.map +1 -0
  118. package/src/lib/guards/lib/_is-buff.d.ts +25 -0
  119. package/src/lib/guards/lib/_is-buff.js +29 -0
  120. package/src/lib/guards/lib/_is-buff.js.map +1 -0
  121. package/src/lib/guards/lib/_is-ctor.d.ts +25 -0
  122. package/src/lib/guards/lib/_is-ctor.js +30 -0
  123. package/src/lib/guards/lib/_is-ctor.js.map +1 -0
  124. package/src/lib/guards/lib/_is-empty-str-or-arr.d.ts +25 -0
  125. package/src/lib/guards/lib/_is-empty-str-or-arr.js +29 -0
  126. package/src/lib/guards/lib/_is-empty-str-or-arr.js.map +1 -0
  127. package/src/lib/guards/lib/_is-equality-same-type.d.ts +25 -0
  128. package/src/lib/guards/lib/_is-equality-same-type.js +33 -0
  129. package/src/lib/guards/lib/_is-equality-same-type.js.map +1 -0
  130. package/src/lib/guards/lib/_is-fn-t.d.ts +25 -0
  131. package/src/lib/guards/lib/_is-fn-t.js +27 -0
  132. package/src/lib/guards/lib/_is-fn-t.js.map +1 -0
  133. package/src/lib/guards/lib/_is-length-of.d.ts +47 -0
  134. package/src/lib/guards/lib/_is-length-of.js +49 -0
  135. package/src/lib/guards/lib/_is-length-of.js.map +1 -0
  136. package/src/lib/guards/lib/_is-length.d.ts +25 -0
  137. package/src/lib/guards/lib/_is-length.js +34 -0
  138. package/src/lib/guards/lib/_is-length.js.map +1 -0
  139. package/src/lib/guards/lib/_is-null.d.ts +25 -0
  140. package/src/lib/guards/lib/_is-null.js +27 -0
  141. package/src/lib/guards/lib/_is-null.js.map +1 -0
  142. package/src/lib/guards/lib/_is-num-neg.d.ts +25 -0
  143. package/src/lib/guards/lib/_is-num-neg.js +28 -0
  144. package/src/lib/guards/lib/_is-num-neg.js.map +1 -0
  145. package/src/lib/guards/lib/_is-num-pos.d.ts +25 -0
  146. package/src/lib/guards/lib/_is-num-pos.js +28 -0
  147. package/src/lib/guards/lib/_is-num-pos.js.map +1 -0
  148. package/src/lib/guards/lib/_is-num-t.d.ts +25 -0
  149. package/src/lib/guards/lib/_is-num-t.js +27 -0
  150. package/src/lib/guards/lib/_is-num-t.js.map +1 -0
  151. package/src/lib/guards/lib/_is-num-zero.d.ts +25 -0
  152. package/src/lib/guards/lib/_is-num-zero.js +28 -0
  153. package/src/lib/guards/lib/_is-num-zero.js.map +1 -0
  154. package/src/lib/guards/lib/_is-num.d.ts +26 -0
  155. package/src/lib/guards/lib/_is-num.js +29 -0
  156. package/src/lib/guards/lib/_is-num.js.map +1 -0
  157. package/src/lib/guards/lib/_is-obj-t.d.ts +26 -0
  158. package/src/lib/guards/lib/_is-obj-t.js +28 -0
  159. package/src/lib/guards/lib/_is-obj-t.js.map +1 -0
  160. package/src/lib/guards/lib/_is-obj.d.ts +27 -0
  161. package/src/lib/guards/lib/_is-obj.js +32 -0
  162. package/src/lib/guards/lib/_is-obj.js.map +1 -0
  163. package/src/lib/guards/lib/_is-prim.d.ts +27 -0
  164. package/src/lib/guards/lib/_is-prim.js +35 -0
  165. package/src/lib/guards/lib/_is-prim.js.map +1 -0
  166. package/src/lib/guards/lib/_is-promise-like.d.ts +24 -0
  167. package/src/lib/guards/lib/_is-promise-like.js +28 -0
  168. package/src/lib/guards/lib/_is-promise-like.js.map +1 -0
  169. package/src/lib/guards/lib/_is-str-empty.d.ts +25 -0
  170. package/src/lib/guards/lib/_is-str-empty.js +28 -0
  171. package/src/lib/guards/lib/_is-str-empty.js.map +1 -0
  172. package/src/lib/guards/lib/_is-str-t.d.ts +26 -0
  173. package/src/lib/guards/lib/_is-str-t.js +28 -0
  174. package/src/lib/guards/lib/_is-str-t.js.map +1 -0
  175. package/src/lib/guards/lib/_is-sym-t.d.ts +25 -0
  176. package/src/lib/guards/lib/_is-sym-t.js +27 -0
  177. package/src/lib/guards/lib/_is-sym-t.js.map +1 -0
  178. package/src/lib/guards/lib/_is-und-or-null.d.ts +25 -0
  179. package/src/lib/guards/lib/_is-und-or-null.js +29 -0
  180. package/src/lib/guards/lib/_is-und-or-null.js.map +1 -0
  181. package/src/lib/guards/lib/_is-und-t.d.ts +25 -0
  182. package/src/lib/guards/lib/_is-und-t.js +27 -0
  183. package/src/lib/guards/lib/_is-und-t.js.map +1 -0
  184. package/src/lib/interop-default.d.ts +18 -0
  185. package/src/lib/interop-default.js +21 -0
  186. package/src/lib/interop-default.js.map +1 -0
  187. package/src/lib/length.d.ts +22 -0
  188. package/src/lib/length.js +28 -0
  189. package/src/lib/length.js.map +1 -0
  190. package/src/lib/linear-regex.d.ts +136 -0
  191. package/src/lib/linear-regex.js +1140 -0
  192. package/src/lib/linear-regex.js.map +1 -0
  193. package/src/lib/no-side-effects.d.ts +29 -0
  194. package/src/lib/no-side-effects.js +33 -0
  195. package/src/lib/no-side-effects.js.map +1 -0
  196. package/src/lib/noop.d.ts +21 -0
  197. package/src/lib/noop.js +22 -0
  198. package/src/lib/noop.js.map +1 -0
  199. package/src/lib/normalized.d.ts +164 -0
  200. package/src/lib/normalized.js +232 -0
  201. package/src/lib/normalized.js.map +1 -0
  202. package/src/lib/number/number-from-hexadecimal.d.ts +24 -0
  203. package/src/lib/number/number-from-hexadecimal.js +29 -0
  204. package/src/lib/number/number-from-hexadecimal.js.map +1 -0
  205. package/src/lib/number/number-to-hexadecimal.d.ts +22 -0
  206. package/src/lib/number/number-to-hexadecimal.js +24 -0
  207. package/src/lib/number/number-to-hexadecimal.js.map +1 -0
  208. package/src/lib/number/to-num.d.ts +41 -0
  209. package/src/lib/number/to-num.js +41 -0
  210. package/src/lib/number/to-num.js.map +1 -0
  211. package/src/lib/numeronym.d.ts +41 -0
  212. package/src/lib/numeronym.js +54 -0
  213. package/src/lib/numeronym.js.map +1 -0
  214. package/src/lib/object/object-clone-deep.d.ts +21 -0
  215. package/src/lib/object/object-clone-deep.js +24 -0
  216. package/src/lib/object/object-clone-deep.js.map +1 -0
  217. package/src/lib/object/object-clone.d.ts +21 -0
  218. package/src/lib/object/object-clone.js +24 -0
  219. package/src/lib/object/object-clone.js.map +1 -0
  220. package/src/lib/object/object-delete-property.d.ts +28 -0
  221. package/src/lib/object/object-delete-property.js +32 -0
  222. package/src/lib/object/object-delete-property.js.map +1 -0
  223. package/src/lib/object/object-get-deep-property.d.ts +35 -0
  224. package/src/lib/object/object-get-deep-property.js +40 -0
  225. package/src/lib/object/object-get-deep-property.js.map +1 -0
  226. package/src/lib/object/object-get-keys-and-symbol-properties.d.ts +23 -0
  227. package/src/lib/object/object-get-keys-and-symbol-properties.js +30 -0
  228. package/src/lib/object/object-get-keys-and-symbol-properties.js.map +1 -0
  229. package/src/lib/object/object-remap.d.ts +33 -0
  230. package/src/lib/object/object-remap.js +36 -0
  231. package/src/lib/object/object-remap.js.map +1 -0
  232. package/src/lib/object/object-safe.d.ts +27 -0
  233. package/src/lib/object/object-safe.js +30 -0
  234. package/src/lib/object/object-safe.js.map +1 -0
  235. package/src/lib/object/object-set-deep-property.d.ts +35 -0
  236. package/src/lib/object/object-set-deep-property.js +44 -0
  237. package/src/lib/object/object-set-deep-property.js.map +1 -0
  238. package/src/lib/object/object-update.d.ts +28 -0
  239. package/src/lib/object/object-update.js +32 -0
  240. package/src/lib/object/object-update.js.map +1 -0
  241. package/src/lib/operator/compare.d.ts +26 -0
  242. package/src/lib/operator/compare.js +42 -0
  243. package/src/lib/operator/compare.js.map +1 -0
  244. package/src/lib/operator/definitions.d.ts +184 -0
  245. package/src/lib/operator/definitions.js +110 -0
  246. package/src/lib/operator/definitions.js.map +1 -0
  247. package/src/lib/operator/index.d.ts +19 -0
  248. package/src/lib/operator/index.js +20 -0
  249. package/src/lib/operator/index.js.map +1 -0
  250. package/src/lib/operator/inference.d.ts +66 -0
  251. package/src/lib/operator/inference.js +60 -0
  252. package/src/lib/operator/inference.js.map +1 -0
  253. package/src/lib/secret-box.d.ts +152 -0
  254. package/src/lib/secret-box.js +263 -0
  255. package/src/lib/secret-box.js.map +1 -0
  256. package/src/lib/serialize/base64-isomorphic-decode.d.ts +23 -0
  257. package/src/lib/serialize/base64-isomorphic-decode.js +28 -0
  258. package/src/lib/serialize/base64-isomorphic-decode.js.map +1 -0
  259. package/src/lib/serialize/base64-isomorphic-encode.d.ts +23 -0
  260. package/src/lib/serialize/base64-isomorphic-encode.js +28 -0
  261. package/src/lib/serialize/base64-isomorphic-encode.js.map +1 -0
  262. package/src/lib/serialize/json-deserialize.d.ts +25 -0
  263. package/src/lib/serialize/json-deserialize.js +27 -0
  264. package/src/lib/serialize/json-deserialize.js.map +1 -0
  265. package/src/lib/serialize/json-serialize.d.ts +25 -0
  266. package/src/lib/serialize/json-serialize.js +27 -0
  267. package/src/lib/serialize/json-serialize.js.map +1 -0
  268. package/src/lib/serialize/php-serial-deserialize-from-byte-stream.d.ts +77 -0
  269. package/src/lib/serialize/php-serial-deserialize-from-byte-stream.js +77 -0
  270. package/src/lib/serialize/php-serial-deserialize-from-byte-stream.js.map +1 -0
  271. package/src/lib/serialize/php-serial-is-serialized-byte-stream.d.ts +77 -0
  272. package/src/lib/serialize/php-serial-is-serialized-byte-stream.js +77 -0
  273. package/src/lib/serialize/php-serial-is-serialized-byte-stream.js.map +1 -0
  274. package/src/lib/serialize/php-serial-serialize-to-byte-stream.d.ts +77 -0
  275. package/src/lib/serialize/php-serial-serialize-to-byte-stream.js +77 -0
  276. package/src/lib/serialize/php-serial-serialize-to-byte-stream.js.map +1 -0
  277. package/src/lib/split-display-name.d.ts +36 -0
  278. package/src/lib/split-display-name.js +47 -0
  279. package/src/lib/split-display-name.js.map +1 -0
  280. package/src/lib/str.d.ts +21 -0
  281. package/src/lib/str.js +23 -0
  282. package/src/lib/str.js.map +1 -0
  283. package/src/lib/trim.d.ts +25 -0
  284. package/src/lib/trim.js +28 -0
  285. package/src/lib/trim.js.map +1 -0
  286. package/src/lib/truthy.d.ts +23 -0
  287. package/src/lib/truthy.js +30 -0
  288. package/src/lib/truthy.js.map +1 -0
@@ -0,0 +1,152 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * A SECRET BOX: a short secret sealed at rest with AES-256-GCM.
19
+ *
20
+ * For a value the platform must be able to read back — a provider refresh
21
+ * token, a webhook signing key — and must never store in the clear. Hashing
22
+ * is the right tool for a secret that is only ever COMPARED (an API key);
23
+ * this is for one that is USED.
24
+ *
25
+ * ## Server-only, and never on the barrel
26
+ *
27
+ * It imports `node:crypto`, so it is reached by its own subpath —
28
+ * `@aglyn/shared-util-tools/secret-box` — and the library index does not
29
+ * re-export it. A browser bundle that pulled this in would fail to build,
30
+ * and one that did not fail would be shipping key handling to a page.
31
+ *
32
+ * It reads no environment. The caller resolves its key material from wherever
33
+ * that caller's credential lives and hands it in, so which process may hold a
34
+ * key is decided by the caller's location, not by this module.
35
+ *
36
+ * ## The sealed form
37
+ *
38
+ * sb1.<keyId>.<iv>.<ciphertext>.<tag>
39
+ *
40
+ * Each part after the key id is base64url. The IV is 12 random bytes per seal
41
+ * and the tag is GCM's full 16 bytes. The version and the key id are bound
42
+ * into the tag as additional authenticated data, so neither can be rewritten
43
+ * to make a sealed value open under a different key or scheme.
44
+ *
45
+ * ## Context
46
+ *
47
+ * A caller may bind a sealed value to where it belongs — a document path, a
48
+ * purpose — by passing the same `context` to seal and open. The context is
49
+ * authenticated, never stored, so a value copied from one record into another
50
+ * refuses to open there, even under the right key.
51
+ *
52
+ * ## Rotation
53
+ *
54
+ * A key carries an id, and a sealed value names the id it was sealed under. A
55
+ * keyring holds the current key, which seals, and any number of earlier keys,
56
+ * which only open. Rotating is: put the new key first, keep the old one after
57
+ * it until nothing sealed under it remains, then drop it. {@link openSecret}
58
+ * reports which key opened a value, so a reader can reseal under the current
59
+ * key as it goes ({@link needsReseal}).
60
+ *
61
+ * ## Refusals
62
+ *
63
+ * Every failure throws {@link SecretBoxError} with a stable code and a message
64
+ * that never contains the plaintext, the ciphertext or key material.
65
+ * Authentication failure is one code, `refused`, whether the ciphertext was
66
+ * altered, the key is wrong or the context differs: GCM cannot tell those
67
+ * apart, and a caller has no business treating them differently.
68
+ */
69
+ /** The version tag every sealed value starts with. */
70
+ export declare const SECRET_BOX_VERSION = "sb1";
71
+ /** Bytes of key material: AES-256. */
72
+ export declare const SECRET_BOX_KEY_BYTES = 32;
73
+ /** Why a key could not be parsed or a value could not be sealed or opened. */
74
+ export type SecretBoxErrorCode =
75
+ /** Key material that is not 32 bytes of base64, or an unusable key id. */
76
+ 'invalid-key'
77
+ /** Not a sealed value at all: wrong shape, bad encoding, wrong lengths. */
78
+ | 'malformed'
79
+ /** A sealed value from a scheme version this module does not open. */
80
+ | 'unsupported-version'
81
+ /** Sealed under a key id the keyring does not hold. */
82
+ | 'unknown-key'
83
+ /** Authentication failed: altered, wrong key, or a different context. */
84
+ | 'refused';
85
+ export declare class SecretBoxError extends Error {
86
+ readonly code: SecretBoxErrorCode;
87
+ constructor(code: SecretBoxErrorCode, message: string);
88
+ }
89
+ /** One key: its id and its 32 bytes. */
90
+ export interface SecretBoxKey {
91
+ readonly id: string;
92
+ readonly material: Uint8Array;
93
+ }
94
+ /**
95
+ * The keys a reader holds. `current` seals; every entry of `keys` — `current`
96
+ * included, first — opens.
97
+ */
98
+ export interface SecretBoxKeyring {
99
+ readonly current: SecretBoxKey;
100
+ readonly keys: readonly SecretBoxKey[];
101
+ }
102
+ /** What opening a sealed value produced. */
103
+ export interface OpenedSecret {
104
+ readonly plaintext: string;
105
+ /** The id of the key that opened it. */
106
+ readonly keyId: string;
107
+ }
108
+ /**
109
+ * The id a key is known by when none is given: eight characters derived from
110
+ * the key itself with HMAC, so it names the key without being a hash of it
111
+ * anyone could test a guess against.
112
+ */
113
+ export declare function deriveSecretBoxKeyId(material: Uint8Array): string;
114
+ /**
115
+ * A key from base64 material (standard or URL-safe), with an explicit id or
116
+ * the derived one.
117
+ */
118
+ export declare function createSecretBoxKey(material: Uint8Array | string, id?: string): SecretBoxKey;
119
+ /**
120
+ * A keyring from one configuration value: keys separated by commas or
121
+ * whitespace, the first the current one. Each entry is base64 material, or
122
+ * `id:material` to name it explicitly.
123
+ *
124
+ * Refuses an empty value, any unparseable entry and two entries with one id —
125
+ * a reader could not know which of the two a sealed value meant.
126
+ */
127
+ export declare function parseSecretBoxKeyring(value: string): SecretBoxKeyring;
128
+ /**
129
+ * Seals a string under a key.
130
+ *
131
+ * `context` is bound into the tag, and the same value must be passed to
132
+ * {@link openSecret}. `iv` is a test seam for a deterministic IV; never pass
133
+ * one in production, because a repeated IV under one key breaks GCM entirely.
134
+ */
135
+ export declare function sealSecret(plaintext: string, key: SecretBoxKey, options?: {
136
+ context?: string;
137
+ iv?: Uint8Array;
138
+ }): string;
139
+ /**
140
+ * Opens a sealed value with whichever key in the ring it names.
141
+ *
142
+ * Throws {@link SecretBoxError}: `malformed` for anything not shaped like a
143
+ * sealed value, `unsupported-version`, `unknown-key` when the ring has no key
144
+ * by that id, and `refused` when authentication fails.
145
+ */
146
+ export declare function openSecret(sealed: string, keys: SecretBoxKeyring | SecretBoxKey | readonly SecretBoxKey[], options?: {
147
+ context?: string;
148
+ }): OpenedSecret;
149
+ /** Whether a value opened under an earlier key and should be sealed again. */
150
+ export declare function needsReseal(opened: OpenedSecret, keyring: SecretBoxKeyring): boolean;
151
+ /** The id of the key a sealed value names, or `null` when it is not one. */
152
+ export declare function sealedSecretKeyId(sealed: unknown): string | null;
@@ -0,0 +1,263 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { createCipheriv, createDecipheriv, createHmac, randomBytes } from "node:crypto";
17
+ /**
18
+ * A SECRET BOX: a short secret sealed at rest with AES-256-GCM.
19
+ *
20
+ * For a value the platform must be able to read back — a provider refresh
21
+ * token, a webhook signing key — and must never store in the clear. Hashing
22
+ * is the right tool for a secret that is only ever COMPARED (an API key);
23
+ * this is for one that is USED.
24
+ *
25
+ * ## Server-only, and never on the barrel
26
+ *
27
+ * It imports `node:crypto`, so it is reached by its own subpath —
28
+ * `@aglyn/shared-util-tools/secret-box` — and the library index does not
29
+ * re-export it. A browser bundle that pulled this in would fail to build,
30
+ * and one that did not fail would be shipping key handling to a page.
31
+ *
32
+ * It reads no environment. The caller resolves its key material from wherever
33
+ * that caller's credential lives and hands it in, so which process may hold a
34
+ * key is decided by the caller's location, not by this module.
35
+ *
36
+ * ## The sealed form
37
+ *
38
+ * sb1.<keyId>.<iv>.<ciphertext>.<tag>
39
+ *
40
+ * Each part after the key id is base64url. The IV is 12 random bytes per seal
41
+ * and the tag is GCM's full 16 bytes. The version and the key id are bound
42
+ * into the tag as additional authenticated data, so neither can be rewritten
43
+ * to make a sealed value open under a different key or scheme.
44
+ *
45
+ * ## Context
46
+ *
47
+ * A caller may bind a sealed value to where it belongs — a document path, a
48
+ * purpose — by passing the same `context` to seal and open. The context is
49
+ * authenticated, never stored, so a value copied from one record into another
50
+ * refuses to open there, even under the right key.
51
+ *
52
+ * ## Rotation
53
+ *
54
+ * A key carries an id, and a sealed value names the id it was sealed under. A
55
+ * keyring holds the current key, which seals, and any number of earlier keys,
56
+ * which only open. Rotating is: put the new key first, keep the old one after
57
+ * it until nothing sealed under it remains, then drop it. {@link openSecret}
58
+ * reports which key opened a value, so a reader can reseal under the current
59
+ * key as it goes ({@link needsReseal}).
60
+ *
61
+ * ## Refusals
62
+ *
63
+ * Every failure throws {@link SecretBoxError} with a stable code and a message
64
+ * that never contains the plaintext, the ciphertext or key material.
65
+ * Authentication failure is one code, `refused`, whether the ciphertext was
66
+ * altered, the key is wrong or the context differs: GCM cannot tell those
67
+ * apart, and a caller has no business treating them differently.
68
+ */ /** The version tag every sealed value starts with. */ export const SECRET_BOX_VERSION = 'sb1';
69
+ /** Bytes of key material: AES-256. */ export const SECRET_BOX_KEY_BYTES = 32;
70
+ const IV_BYTES = 12;
71
+ const TAG_BYTES = 16;
72
+ const ALGORITHM = 'aes-256-gcm';
73
+ /** A key id: short, URL-safe and free of the separator. */ const KEY_ID = /^[A-Za-z0-9_-]{1,32}$/;
74
+ /** Standard or URL-safe base64, padded or not. */ const BASE64 = /^[A-Za-z0-9+/_-]+={0,2}$/;
75
+ /** Unpadded base64url, the only alphabet a sealed value uses. */ const BASE64URL = /^[A-Za-z0-9_-]+$/;
76
+ export class SecretBoxError extends Error {
77
+ constructor(code, message){
78
+ super(message);
79
+ this.name = 'SecretBoxError';
80
+ this.code = code;
81
+ }
82
+ }
83
+ const toBase64Url = (bytes)=>Buffer.from(bytes).toString('base64url');
84
+ function decodeBase64Url(part, expectedBytes) {
85
+ if (!BASE64URL.test(part)) {
86
+ throw new SecretBoxError('malformed', 'The sealed value is not valid base64url.');
87
+ }
88
+ const bytes = Buffer.from(part, 'base64url');
89
+ // Re-encoding catches a part with trailing bits Node's decoder silently
90
+ // dropped, which would otherwise be two spellings of one value.
91
+ if (toBase64Url(bytes) !== part) {
92
+ throw new SecretBoxError('malformed', 'The sealed value is not canonical base64url.');
93
+ }
94
+ if (expectedBytes !== undefined && bytes.length !== expectedBytes) {
95
+ throw new SecretBoxError('malformed', 'A part of the sealed value has the wrong length.');
96
+ }
97
+ return bytes;
98
+ }
99
+ /**
100
+ * The id a key is known by when none is given: eight characters derived from
101
+ * the key itself with HMAC, so it names the key without being a hash of it
102
+ * anyone could test a guess against.
103
+ */ export function deriveSecretBoxKeyId(material) {
104
+ return createHmac('sha256', Buffer.from(material)).update('secret-box:key-id').digest().subarray(0, 6).toString('base64url');
105
+ }
106
+ /**
107
+ * A key from base64 material (standard or URL-safe), with an explicit id or
108
+ * the derived one.
109
+ */ export function createSecretBoxKey(material, id) {
110
+ let bytes;
111
+ if (typeof material === 'string') {
112
+ const trimmed = material.trim();
113
+ if (!BASE64.test(trimmed)) {
114
+ throw new SecretBoxError('invalid-key', 'A secret box key must be base64.');
115
+ }
116
+ bytes = Buffer.from(trimmed.replace(/-/g, '+').replace(/_/g, '/'), 'base64');
117
+ } else {
118
+ bytes = Buffer.from(material);
119
+ }
120
+ if (bytes.length !== SECRET_BOX_KEY_BYTES) {
121
+ throw new SecretBoxError('invalid-key', `A secret box key must be ${SECRET_BOX_KEY_BYTES} bytes.`);
122
+ }
123
+ const keyId = id != null ? id : deriveSecretBoxKeyId(bytes);
124
+ if (!KEY_ID.test(keyId)) {
125
+ throw new SecretBoxError('invalid-key', 'A secret box key id must be 1-32 letters, digits, "-" or "_".');
126
+ }
127
+ return {
128
+ id: keyId,
129
+ material: bytes
130
+ };
131
+ }
132
+ /**
133
+ * A keyring from one configuration value: keys separated by commas or
134
+ * whitespace, the first the current one. Each entry is base64 material, or
135
+ * `id:material` to name it explicitly.
136
+ *
137
+ * Refuses an empty value, any unparseable entry and two entries with one id —
138
+ * a reader could not know which of the two a sealed value meant.
139
+ */ export function parseSecretBoxKeyring(value) {
140
+ const entries = String(value != null ? value : '').split(/[\s,]+/).map((entry)=>entry.trim()).filter(Boolean);
141
+ if (!entries.length) {
142
+ throw new SecretBoxError('invalid-key', 'No secret box key was given.');
143
+ }
144
+ const keys = entries.map((entry)=>{
145
+ const separator = entry.indexOf(':');
146
+ return separator > 0 ? createSecretBoxKey(entry.slice(separator + 1), entry.slice(0, separator)) : createSecretBoxKey(entry);
147
+ });
148
+ const ids = new Set();
149
+ for (const key of keys){
150
+ if (ids.has(key.id)) {
151
+ throw new SecretBoxError('invalid-key', 'Two secret box keys share one id.');
152
+ }
153
+ ids.add(key.id);
154
+ }
155
+ return {
156
+ current: keys[0],
157
+ keys
158
+ };
159
+ }
160
+ function asKeyring(keys) {
161
+ if (Array.isArray(keys)) return keys;
162
+ if ('current' in keys) {
163
+ return keys.keys;
164
+ }
165
+ return [
166
+ keys
167
+ ];
168
+ }
169
+ /** Version and key id, then the caller's context, as authenticated data. */ function additionalData(keyId, context) {
170
+ return Buffer.from(`${SECRET_BOX_VERSION}\u0000${keyId}\u0000${context != null ? context : ''}`, 'utf8');
171
+ }
172
+ /**
173
+ * Seals a string under a key.
174
+ *
175
+ * `context` is bound into the tag, and the same value must be passed to
176
+ * {@link openSecret}. `iv` is a test seam for a deterministic IV; never pass
177
+ * one in production, because a repeated IV under one key breaks GCM entirely.
178
+ */ export function sealSecret(plaintext, key, options = {}) {
179
+ var _key_material;
180
+ if (typeof plaintext !== 'string') {
181
+ throw new SecretBoxError('malformed', 'Only a string can be sealed.');
182
+ }
183
+ if (!key || ((_key_material = key.material) == null ? void 0 : _key_material.length) !== SECRET_BOX_KEY_BYTES || !KEY_ID.test(key.id)) {
184
+ throw new SecretBoxError('invalid-key', 'The sealing key is not a usable secret box key.');
185
+ }
186
+ const iv = options.iv ? Buffer.from(options.iv) : randomBytes(IV_BYTES);
187
+ if (iv.length !== IV_BYTES) {
188
+ throw new SecretBoxError('malformed', `A secret box IV must be ${IV_BYTES} bytes.`);
189
+ }
190
+ const cipher = createCipheriv(ALGORITHM, Buffer.from(key.material), iv, {
191
+ authTagLength: TAG_BYTES
192
+ });
193
+ cipher.setAAD(additionalData(key.id, options.context));
194
+ const ciphertext = Buffer.concat([
195
+ cipher.update(plaintext, 'utf8'),
196
+ cipher.final()
197
+ ]);
198
+ const tag = cipher.getAuthTag();
199
+ return [
200
+ SECRET_BOX_VERSION,
201
+ key.id,
202
+ toBase64Url(iv),
203
+ toBase64Url(ciphertext),
204
+ toBase64Url(tag)
205
+ ].join('.');
206
+ }
207
+ /**
208
+ * Opens a sealed value with whichever key in the ring it names.
209
+ *
210
+ * Throws {@link SecretBoxError}: `malformed` for anything not shaped like a
211
+ * sealed value, `unsupported-version`, `unknown-key` when the ring has no key
212
+ * by that id, and `refused` when authentication fails.
213
+ */ export function openSecret(sealed, keys, options = {}) {
214
+ if (typeof sealed !== 'string' || !sealed) {
215
+ throw new SecretBoxError('malformed', 'The sealed value is empty.');
216
+ }
217
+ const parts = sealed.split('.');
218
+ if (parts.length !== 5) {
219
+ throw new SecretBoxError('malformed', 'The sealed value does not have five parts.');
220
+ }
221
+ const [version, keyId, ivPart, ciphertextPart, tagPart] = parts;
222
+ if (version !== SECRET_BOX_VERSION) {
223
+ throw new SecretBoxError('unsupported-version', 'The sealed value was made by a scheme this reader does not open.');
224
+ }
225
+ if (!KEY_ID.test(keyId)) {
226
+ throw new SecretBoxError('malformed', 'The sealed value names an unusable key id.');
227
+ }
228
+ const iv = decodeBase64Url(ivPart, IV_BYTES);
229
+ // An empty ciphertext is a sealed empty string, and legitimate.
230
+ const ciphertext = ciphertextPart ? decodeBase64Url(ciphertextPart) : Buffer.alloc(0);
231
+ const tag = decodeBase64Url(tagPart, TAG_BYTES);
232
+ const key = asKeyring(keys).find((candidate)=>candidate.id === keyId);
233
+ if (!key) {
234
+ throw new SecretBoxError('unknown-key', 'The sealed value was sealed under a key this reader does not hold.');
235
+ }
236
+ try {
237
+ const decipher = createDecipheriv(ALGORITHM, Buffer.from(key.material), iv, {
238
+ authTagLength: TAG_BYTES
239
+ });
240
+ decipher.setAAD(additionalData(keyId, options.context));
241
+ decipher.setAuthTag(tag);
242
+ const plaintext = Buffer.concat([
243
+ decipher.update(ciphertext),
244
+ decipher.final()
245
+ ]).toString('utf8');
246
+ return {
247
+ plaintext,
248
+ keyId
249
+ };
250
+ } catch (unused) {
251
+ throw new SecretBoxError('refused', 'The sealed value did not authenticate: it was altered, or the key or context is wrong.');
252
+ }
253
+ }
254
+ /** Whether a value opened under an earlier key and should be sealed again. */ export function needsReseal(opened, keyring) {
255
+ return opened.keyId !== keyring.current.id;
256
+ }
257
+ /** The id of the key a sealed value names, or `null` when it is not one. */ export function sealedSecretKeyId(sealed) {
258
+ if (typeof sealed !== 'string') return null;
259
+ const parts = sealed.split('.');
260
+ return parts.length === 5 && parts[0] === SECRET_BOX_VERSION && KEY_ID.test(parts[1]) ? parts[1] : null;
261
+ }
262
+
263
+ //# sourceMappingURL=secret-box.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/shared/util/tools/src/lib/secret-box.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createCipheriv,\n createDecipheriv,\n createHmac,\n randomBytes,\n} from 'node:crypto'\n\n/**\n * A SECRET BOX: a short secret sealed at rest with AES-256-GCM.\n *\n * For a value the platform must be able to read back — a provider refresh\n * token, a webhook signing key — and must never store in the clear. Hashing\n * is the right tool for a secret that is only ever COMPARED (an API key);\n * this is for one that is USED.\n *\n * ## Server-only, and never on the barrel\n *\n * It imports `node:crypto`, so it is reached by its own subpath —\n * `@aglyn/shared-util-tools/secret-box` — and the library index does not\n * re-export it. A browser bundle that pulled this in would fail to build,\n * and one that did not fail would be shipping key handling to a page.\n *\n * It reads no environment. The caller resolves its key material from wherever\n * that caller's credential lives and hands it in, so which process may hold a\n * key is decided by the caller's location, not by this module.\n *\n * ## The sealed form\n *\n * sb1.<keyId>.<iv>.<ciphertext>.<tag>\n *\n * Each part after the key id is base64url. The IV is 12 random bytes per seal\n * and the tag is GCM's full 16 bytes. The version and the key id are bound\n * into the tag as additional authenticated data, so neither can be rewritten\n * to make a sealed value open under a different key or scheme.\n *\n * ## Context\n *\n * A caller may bind a sealed value to where it belongs — a document path, a\n * purpose — by passing the same `context` to seal and open. The context is\n * authenticated, never stored, so a value copied from one record into another\n * refuses to open there, even under the right key.\n *\n * ## Rotation\n *\n * A key carries an id, and a sealed value names the id it was sealed under. A\n * keyring holds the current key, which seals, and any number of earlier keys,\n * which only open. Rotating is: put the new key first, keep the old one after\n * it until nothing sealed under it remains, then drop it. {@link openSecret}\n * reports which key opened a value, so a reader can reseal under the current\n * key as it goes ({@link needsReseal}).\n *\n * ## Refusals\n *\n * Every failure throws {@link SecretBoxError} with a stable code and a message\n * that never contains the plaintext, the ciphertext or key material.\n * Authentication failure is one code, `refused`, whether the ciphertext was\n * altered, the key is wrong or the context differs: GCM cannot tell those\n * apart, and a caller has no business treating them differently.\n */\n\n/** The version tag every sealed value starts with. */\nexport const SECRET_BOX_VERSION = 'sb1'\n\n/** Bytes of key material: AES-256. */\nexport const SECRET_BOX_KEY_BYTES = 32\n\nconst IV_BYTES = 12\nconst TAG_BYTES = 16\nconst ALGORITHM = 'aes-256-gcm'\n\n/** A key id: short, URL-safe and free of the separator. */\nconst KEY_ID = /^[A-Za-z0-9_-]{1,32}$/\n\n/** Standard or URL-safe base64, padded or not. */\nconst BASE64 = /^[A-Za-z0-9+/_-]+={0,2}$/\n\n/** Unpadded base64url, the only alphabet a sealed value uses. */\nconst BASE64URL = /^[A-Za-z0-9_-]+$/\n\n/** Why a key could not be parsed or a value could not be sealed or opened. */\nexport type SecretBoxErrorCode =\n /** Key material that is not 32 bytes of base64, or an unusable key id. */\n | 'invalid-key'\n /** Not a sealed value at all: wrong shape, bad encoding, wrong lengths. */\n | 'malformed'\n /** A sealed value from a scheme version this module does not open. */\n | 'unsupported-version'\n /** Sealed under a key id the keyring does not hold. */\n | 'unknown-key'\n /** Authentication failed: altered, wrong key, or a different context. */\n | 'refused'\n\nexport class SecretBoxError extends Error {\n readonly code: SecretBoxErrorCode\n\n constructor(code: SecretBoxErrorCode, message: string) {\n super(message)\n this.name = 'SecretBoxError'\n this.code = code\n }\n}\n\n/** One key: its id and its 32 bytes. */\nexport interface SecretBoxKey {\n readonly id: string\n readonly material: Uint8Array\n}\n\n/**\n * The keys a reader holds. `current` seals; every entry of `keys` — `current`\n * included, first — opens.\n */\nexport interface SecretBoxKeyring {\n readonly current: SecretBoxKey\n readonly keys: readonly SecretBoxKey[]\n}\n\n/** What opening a sealed value produced. */\nexport interface OpenedSecret {\n readonly plaintext: string\n /** The id of the key that opened it. */\n readonly keyId: string\n}\n\nconst toBase64Url = (bytes: Uint8Array): string =>\n Buffer.from(bytes).toString('base64url')\n\nfunction decodeBase64Url(part: string, expectedBytes?: number): Buffer {\n if (!BASE64URL.test(part)) {\n throw new SecretBoxError('malformed', 'The sealed value is not valid base64url.')\n }\n const bytes = Buffer.from(part, 'base64url')\n // Re-encoding catches a part with trailing bits Node's decoder silently\n // dropped, which would otherwise be two spellings of one value.\n if (toBase64Url(bytes) !== part) {\n throw new SecretBoxError('malformed', 'The sealed value is not canonical base64url.')\n }\n if (expectedBytes !== undefined && bytes.length !== expectedBytes) {\n throw new SecretBoxError('malformed', 'A part of the sealed value has the wrong length.')\n }\n return bytes\n}\n\n/**\n * The id a key is known by when none is given: eight characters derived from\n * the key itself with HMAC, so it names the key without being a hash of it\n * anyone could test a guess against.\n */\nexport function deriveSecretBoxKeyId(material: Uint8Array): string {\n return createHmac('sha256', Buffer.from(material))\n .update('secret-box:key-id')\n .digest()\n .subarray(0, 6)\n .toString('base64url')\n}\n\n/**\n * A key from base64 material (standard or URL-safe), with an explicit id or\n * the derived one.\n */\nexport function createSecretBoxKey(\n material: Uint8Array | string,\n id?: string,\n): SecretBoxKey {\n let bytes: Buffer\n if (typeof material === 'string') {\n const trimmed = material.trim()\n if (!BASE64.test(trimmed)) {\n throw new SecretBoxError('invalid-key', 'A secret box key must be base64.')\n }\n bytes = Buffer.from(trimmed.replace(/-/g, '+').replace(/_/g, '/'), 'base64')\n } else {\n bytes = Buffer.from(material)\n }\n if (bytes.length !== SECRET_BOX_KEY_BYTES) {\n throw new SecretBoxError(\n 'invalid-key',\n `A secret box key must be ${SECRET_BOX_KEY_BYTES} bytes.`,\n )\n }\n const keyId = id ?? deriveSecretBoxKeyId(bytes)\n if (!KEY_ID.test(keyId)) {\n throw new SecretBoxError(\n 'invalid-key',\n 'A secret box key id must be 1-32 letters, digits, \"-\" or \"_\".',\n )\n }\n return { id: keyId, material: bytes }\n}\n\n/**\n * A keyring from one configuration value: keys separated by commas or\n * whitespace, the first the current one. Each entry is base64 material, or\n * `id:material` to name it explicitly.\n *\n * Refuses an empty value, any unparseable entry and two entries with one id —\n * a reader could not know which of the two a sealed value meant.\n */\nexport function parseSecretBoxKeyring(value: string): SecretBoxKeyring {\n const entries = String(value ?? '')\n .split(/[\\s,]+/)\n .map((entry) => entry.trim())\n .filter(Boolean)\n if (!entries.length) {\n throw new SecretBoxError('invalid-key', 'No secret box key was given.')\n }\n const keys = entries.map((entry) => {\n const separator = entry.indexOf(':')\n return separator > 0\n ? createSecretBoxKey(entry.slice(separator + 1), entry.slice(0, separator))\n : createSecretBoxKey(entry)\n })\n const ids = new Set<string>()\n for (const key of keys) {\n if (ids.has(key.id)) {\n throw new SecretBoxError('invalid-key', 'Two secret box keys share one id.')\n }\n ids.add(key.id)\n }\n return { current: keys[0], keys }\n}\n\nfunction asKeyring(\n keys: SecretBoxKeyring | SecretBoxKey | readonly SecretBoxKey[],\n): readonly SecretBoxKey[] {\n if (Array.isArray(keys)) return keys\n if ('current' in (keys as SecretBoxKeyring)) {\n return (keys as SecretBoxKeyring).keys\n }\n return [keys as SecretBoxKey]\n}\n\n/** Version and key id, then the caller's context, as authenticated data. */\nfunction additionalData(keyId: string, context: string | undefined): Buffer {\n return Buffer.from(`${SECRET_BOX_VERSION}\\u0000${keyId}\\u0000${context ?? ''}`, 'utf8')\n}\n\n/**\n * Seals a string under a key.\n *\n * `context` is bound into the tag, and the same value must be passed to\n * {@link openSecret}. `iv` is a test seam for a deterministic IV; never pass\n * one in production, because a repeated IV under one key breaks GCM entirely.\n */\nexport function sealSecret(\n plaintext: string,\n key: SecretBoxKey,\n options: { context?: string; iv?: Uint8Array } = {},\n): string {\n if (typeof plaintext !== 'string') {\n throw new SecretBoxError('malformed', 'Only a string can be sealed.')\n }\n if (!key || key.material?.length !== SECRET_BOX_KEY_BYTES || !KEY_ID.test(key.id)) {\n throw new SecretBoxError('invalid-key', 'The sealing key is not a usable secret box key.')\n }\n const iv = options.iv ? Buffer.from(options.iv) : randomBytes(IV_BYTES)\n if (iv.length !== IV_BYTES) {\n throw new SecretBoxError('malformed', `A secret box IV must be ${IV_BYTES} bytes.`)\n }\n const cipher = createCipheriv(ALGORITHM, Buffer.from(key.material), iv, {\n authTagLength: TAG_BYTES,\n })\n cipher.setAAD(additionalData(key.id, options.context))\n const ciphertext = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()])\n const tag = cipher.getAuthTag()\n return [\n SECRET_BOX_VERSION,\n key.id,\n toBase64Url(iv),\n toBase64Url(ciphertext),\n toBase64Url(tag),\n ].join('.')\n}\n\n/**\n * Opens a sealed value with whichever key in the ring it names.\n *\n * Throws {@link SecretBoxError}: `malformed` for anything not shaped like a\n * sealed value, `unsupported-version`, `unknown-key` when the ring has no key\n * by that id, and `refused` when authentication fails.\n */\nexport function openSecret(\n sealed: string,\n keys: SecretBoxKeyring | SecretBoxKey | readonly SecretBoxKey[],\n options: { context?: string } = {},\n): OpenedSecret {\n if (typeof sealed !== 'string' || !sealed) {\n throw new SecretBoxError('malformed', 'The sealed value is empty.')\n }\n const parts = sealed.split('.')\n if (parts.length !== 5) {\n throw new SecretBoxError('malformed', 'The sealed value does not have five parts.')\n }\n const [version, keyId, ivPart, ciphertextPart, tagPart] = parts\n if (version !== SECRET_BOX_VERSION) {\n throw new SecretBoxError(\n 'unsupported-version',\n 'The sealed value was made by a scheme this reader does not open.',\n )\n }\n if (!KEY_ID.test(keyId)) {\n throw new SecretBoxError('malformed', 'The sealed value names an unusable key id.')\n }\n const iv = decodeBase64Url(ivPart, IV_BYTES)\n // An empty ciphertext is a sealed empty string, and legitimate.\n const ciphertext = ciphertextPart ? decodeBase64Url(ciphertextPart) : Buffer.alloc(0)\n const tag = decodeBase64Url(tagPart, TAG_BYTES)\n\n const key = asKeyring(keys).find((candidate) => candidate.id === keyId)\n if (!key) {\n throw new SecretBoxError(\n 'unknown-key',\n 'The sealed value was sealed under a key this reader does not hold.',\n )\n }\n try {\n const decipher = createDecipheriv(ALGORITHM, Buffer.from(key.material), iv, {\n authTagLength: TAG_BYTES,\n })\n decipher.setAAD(additionalData(keyId, options.context))\n decipher.setAuthTag(tag)\n const plaintext = Buffer.concat([\n decipher.update(ciphertext),\n decipher.final(),\n ]).toString('utf8')\n return { plaintext, keyId }\n } catch {\n throw new SecretBoxError(\n 'refused',\n 'The sealed value did not authenticate: it was altered, or the key or context is wrong.',\n )\n }\n}\n\n/** Whether a value opened under an earlier key and should be sealed again. */\nexport function needsReseal(opened: OpenedSecret, keyring: SecretBoxKeyring): boolean {\n return opened.keyId !== keyring.current.id\n}\n\n/** The id of the key a sealed value names, or `null` when it is not one. */\nexport function sealedSecretKeyId(sealed: unknown): string | null {\n if (typeof sealed !== 'string') return null\n const parts = sealed.split('.')\n return parts.length === 5 && parts[0] === SECRET_BOX_VERSION && KEY_ID.test(parts[1])\n ? parts[1]\n : null\n}\n"],"names":["createCipheriv","createDecipheriv","createHmac","randomBytes","SECRET_BOX_VERSION","SECRET_BOX_KEY_BYTES","IV_BYTES","TAG_BYTES","ALGORITHM","KEY_ID","BASE64","BASE64URL","SecretBoxError","Error","code","message","name","toBase64Url","bytes","Buffer","from","toString","decodeBase64Url","part","expectedBytes","test","undefined","length","deriveSecretBoxKeyId","material","update","digest","subarray","createSecretBoxKey","id","trimmed","trim","replace","keyId","parseSecretBoxKeyring","value","entries","String","split","map","entry","filter","Boolean","keys","separator","indexOf","slice","ids","Set","key","has","add","current","asKeyring","Array","isArray","additionalData","context","sealSecret","plaintext","options","iv","cipher","authTagLength","setAAD","ciphertext","concat","final","tag","getAuthTag","join","openSecret","sealed","parts","version","ivPart","ciphertextPart","tagPart","alloc","find","candidate","decipher","setAuthTag","needsReseal","opened","keyring","sealedSecretKeyId"],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * Decode a base64 value to unicode string, safely in BOM and Node
19
+ * @param value - the base64 value to decode to unicode
20
+ * @param encoding - character encoding of return value 'utf8'|'utf16'|'unicode'
21
+ */
22
+ export declare function base64IsomorphicDecode(value: string, encoding?: BufferEncoding): string;
23
+ export default base64IsomorphicDecode;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ /**
17
+ * Decode a base64 value to unicode string, safely in BOM and Node
18
+ * @param value - the base64 value to decode to unicode
19
+ * @param encoding - character encoding of return value 'utf8'|'utf16'|'unicode'
20
+ */ export function base64IsomorphicDecode(value, encoding = 'utf8') {
21
+ if (typeof window === 'undefined') {
22
+ return globalThis.Buffer.from(value, 'base64').toString(encoding);
23
+ }
24
+ return window.atob(value);
25
+ }
26
+ export default base64IsomorphicDecode;
27
+
28
+ //# sourceMappingURL=base64-isomorphic-decode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/shared/util/tools/src/lib/serialize/base64-isomorphic-decode.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2022 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Decode a base64 value to unicode string, safely in BOM and Node\n * @param value - the base64 value to decode to unicode\n * @param encoding - character encoding of return value 'utf8'|'utf16'|'unicode'\n */\nexport function base64IsomorphicDecode(\n value: string,\n encoding: BufferEncoding = 'utf8',\n): string {\n if (typeof window === 'undefined') {\n return globalThis.Buffer.from(value, 'base64').toString(encoding)\n }\n return window.atob(value)\n}\nexport default base64IsomorphicDecode\n"],"names":["base64IsomorphicDecode","value","encoding","window","globalThis","Buffer","from","toString","atob"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;CAIC,GACD,OAAO,SAASA,uBACdC,KAAa,EACbC,WAA2B,MAAM;IAEjC,IAAI,OAAOC,WAAW,aAAa;QACjC,OAAOC,WAAWC,MAAM,CAACC,IAAI,CAACL,OAAO,UAAUM,QAAQ,CAACL;IAC1D;IACA,OAAOC,OAAOK,IAAI,CAACP;AACrB;AACA,eAAeD,uBAAsB"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2023 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * Encode a unicode value to base64 string, safely in BOM and Node
19
+ * @param value - the unicode value to encode to base64
20
+ * @param encoding - character encoding of value param 'utf8'|'utf16'|'unicode'
21
+ */
22
+ export declare function base64IsomorphicEncode(value: string, encoding?: BufferEncoding): string;
23
+ export default base64IsomorphicEncode;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2023 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ /**
17
+ * Encode a unicode value to base64 string, safely in BOM and Node
18
+ * @param value - the unicode value to encode to base64
19
+ * @param encoding - character encoding of value param 'utf8'|'utf16'|'unicode'
20
+ */ export function base64IsomorphicEncode(value, encoding = 'utf8') {
21
+ if (typeof window === 'undefined') {
22
+ return globalThis.Buffer.from(value, encoding).toString('base64');
23
+ }
24
+ return window.btoa(value);
25
+ }
26
+ export default base64IsomorphicEncode;
27
+
28
+ //# sourceMappingURL=base64-isomorphic-encode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/shared/util/tools/src/lib/serialize/base64-isomorphic-encode.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2023 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Encode a unicode value to base64 string, safely in BOM and Node\n * @param value - the unicode value to encode to base64\n * @param encoding - character encoding of value param 'utf8'|'utf16'|'unicode'\n */\nexport function base64IsomorphicEncode(\n value: string,\n encoding: BufferEncoding = 'utf8',\n): string {\n if (typeof window === 'undefined') {\n return globalThis.Buffer.from(value, encoding).toString('base64')\n }\n return window.btoa(value)\n}\nexport default base64IsomorphicEncode\n"],"names":["base64IsomorphicEncode","value","encoding","window","globalThis","Buffer","from","toString","btoa"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;CAIC,GACD,OAAO,SAASA,uBACdC,KAAa,EACbC,WAA2B,MAAM;IAEjC,IAAI,OAAOC,WAAW,aAAa;QACjC,OAAOC,WAAWC,MAAM,CAACC,IAAI,CAACL,OAAOC,UAAUK,QAAQ,CAAC;IAC1D;IACA,OAAOJ,OAAOK,IAAI,CAACP;AACrB;AACA,eAAeD,uBAAsB"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * Generates a value into a **_JSON_** parsing representation of a value
19
+ *
20
+ * @see {@link jsonSerialize}
21
+ * @see {@link JSON.parse}
22
+ * @see {@link JSON.stringify}
23
+ */
24
+ export declare function jsonDeserialize(...args: Parameters<typeof JSON.parse>): ReturnType<typeof JSON.parse>;
25
+ export default jsonDeserialize;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ /**
17
+ * Generates a value into a **_JSON_** parsing representation of a value
18
+ *
19
+ * @see {@link jsonSerialize}
20
+ * @see {@link JSON.parse}
21
+ * @see {@link JSON.stringify}
22
+ */ export function jsonDeserialize(...args) {
23
+ return JSON.parse(...args);
24
+ }
25
+ export default jsonDeserialize;
26
+
27
+ //# sourceMappingURL=json-deserialize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/shared/util/tools/src/lib/serialize/json-deserialize.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2022 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Generates a value into a **_JSON_** parsing representation of a value\n *\n * @see {@link jsonSerialize}\n * @see {@link JSON.parse}\n * @see {@link JSON.stringify}\n */\nexport function jsonDeserialize(...args: Parameters<typeof JSON.parse>): ReturnType<typeof JSON.parse> {\n return JSON.parse(...args)\n}\nexport default jsonDeserialize\n"],"names":["jsonDeserialize","args","JSON","parse"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;CAMC,GACD,OAAO,SAASA,gBAAgB,GAAGC,IAAmC;IACpE,OAAOC,KAAKC,KAAK,IAAIF;AACvB;AACA,eAAeD,gBAAe"}