@enbox/dwn-sdk-js 0.4.6 → 0.4.8

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 (375) hide show
  1. package/README.md +3 -1
  2. package/dist/browser.mjs +19 -78
  3. package/dist/browser.mjs.map +4 -4
  4. package/dist/esm/generated/precompiled-validators.js +2324 -1525
  5. package/dist/esm/generated/precompiled-validators.js.map +1 -1
  6. package/dist/esm/src/core/constants.js +50 -0
  7. package/dist/esm/src/core/constants.js.map +1 -1
  8. package/dist/esm/src/core/dwn-error.js +29 -11
  9. package/dist/esm/src/core/dwn-error.js.map +1 -1
  10. package/dist/esm/src/core/encryption-control.js +785 -0
  11. package/dist/esm/src/core/encryption-control.js.map +1 -0
  12. package/dist/esm/src/core/message.js +6 -0
  13. package/dist/esm/src/core/message.js.map +1 -1
  14. package/dist/esm/src/core/messages-grant-authorization.js +36 -5
  15. package/dist/esm/src/core/messages-grant-authorization.js.map +1 -1
  16. package/dist/esm/src/core/protocol-authorization-action.js +3 -12
  17. package/dist/esm/src/core/protocol-authorization-action.js.map +1 -1
  18. package/dist/esm/src/core/protocol-authorization-validation.js +31 -30
  19. package/dist/esm/src/core/protocol-authorization-validation.js.map +1 -1
  20. package/dist/esm/src/core/protocol-authorization.js +6 -0
  21. package/dist/esm/src/core/protocol-authorization.js.map +1 -1
  22. package/dist/esm/src/core/recording-validation-state-reader.js +3 -3
  23. package/dist/esm/src/core/recording-validation-state-reader.js.map +1 -1
  24. package/dist/esm/src/core/replication-apply.js +62 -108
  25. package/dist/esm/src/core/replication-apply.js.map +1 -1
  26. package/dist/esm/src/core/validation-state-reader.js +5 -6
  27. package/dist/esm/src/core/validation-state-reader.js.map +1 -1
  28. package/dist/esm/src/dwn.js +1 -2
  29. package/dist/esm/src/dwn.js.map +1 -1
  30. package/dist/esm/src/event-stream/event-emitter-wake-publisher.js +11 -11
  31. package/dist/esm/src/event-stream/event-emitter-wake-publisher.js.map +1 -1
  32. package/dist/esm/src/handlers/messages-query.js +6 -16
  33. package/dist/esm/src/handlers/messages-query.js.map +1 -1
  34. package/dist/esm/src/handlers/messages-read.js +4 -3
  35. package/dist/esm/src/handlers/messages-read.js.map +1 -1
  36. package/dist/esm/src/handlers/messages-subscribe.js +26 -30
  37. package/dist/esm/src/handlers/messages-subscribe.js.map +1 -1
  38. package/dist/esm/src/handlers/protocols-configure.js +6 -4
  39. package/dist/esm/src/handlers/protocols-configure.js.map +1 -1
  40. package/dist/esm/src/handlers/records-count.js +85 -10
  41. package/dist/esm/src/handlers/records-count.js.map +1 -1
  42. package/dist/esm/src/handlers/records-delete.js +11 -0
  43. package/dist/esm/src/handlers/records-delete.js.map +1 -1
  44. package/dist/esm/src/handlers/records-query.js +140 -18
  45. package/dist/esm/src/handlers/records-query.js.map +1 -1
  46. package/dist/esm/src/handlers/records-read.js +20 -4
  47. package/dist/esm/src/handlers/records-read.js.map +1 -1
  48. package/dist/esm/src/handlers/records-subscribe.js +127 -11
  49. package/dist/esm/src/handlers/records-subscribe.js.map +1 -1
  50. package/dist/esm/src/handlers/records-write.js +15 -0
  51. package/dist/esm/src/handlers/records-write.js.map +1 -1
  52. package/dist/esm/src/index.js +8 -11
  53. package/dist/esm/src/index.js.map +1 -1
  54. package/dist/esm/src/interfaces/protocols-configure.js +66 -9
  55. package/dist/esm/src/interfaces/protocols-configure.js.map +1 -1
  56. package/dist/esm/src/interfaces/records-write.js +43 -36
  57. package/dist/esm/src/interfaces/records-write.js.map +1 -1
  58. package/dist/esm/src/jose/algorithms/signing/ed25519.js +5 -5
  59. package/dist/esm/src/jose/algorithms/signing/ed25519.js.map +1 -1
  60. package/dist/esm/src/jose/jws/general/verifier.js +1 -1
  61. package/dist/esm/src/jose/jws/general/verifier.js.map +1 -1
  62. package/dist/esm/src/protocols/encryption.js +60 -270
  63. package/dist/esm/src/protocols/encryption.js.map +1 -1
  64. package/dist/esm/src/store/blockstore-level.js +14 -23
  65. package/dist/esm/src/store/blockstore-level.js.map +1 -1
  66. package/dist/esm/src/store/blockstore-mock.js +10 -27
  67. package/dist/esm/src/store/blockstore-mock.js.map +1 -1
  68. package/dist/esm/src/store/blockstore-utils.js +45 -0
  69. package/dist/esm/src/store/blockstore-utils.js.map +1 -0
  70. package/dist/esm/src/store/blockstore.js +2 -0
  71. package/dist/esm/src/store/blockstore.js.map +1 -0
  72. package/dist/esm/src/store/data-store-level.js +4 -12
  73. package/dist/esm/src/store/data-store-level.js.map +1 -1
  74. package/dist/esm/src/store/level.js +7 -0
  75. package/dist/esm/src/store/level.js.map +1 -0
  76. package/dist/esm/src/types/encryption-types.js +4 -1
  77. package/dist/esm/src/types/encryption-types.js.map +1 -1
  78. package/dist/esm/src/utils/data-stream.js +25 -0
  79. package/dist/esm/src/utils/data-stream.js.map +1 -1
  80. package/dist/esm/src/utils/encryption.js +107 -19
  81. package/dist/esm/src/utils/encryption.js.map +1 -1
  82. package/dist/esm/src/utils/grant-key-coverage.js +180 -0
  83. package/dist/esm/src/utils/grant-key-coverage.js.map +1 -0
  84. package/dist/esm/src/utils/hd-key.js +1 -2
  85. package/dist/esm/src/utils/hd-key.js.map +1 -1
  86. package/dist/esm/src/utils/jws.js +7 -1
  87. package/dist/esm/src/utils/jws.js.map +1 -1
  88. package/dist/esm/src/utils/memory-cache.js +29 -8
  89. package/dist/esm/src/utils/memory-cache.js.map +1 -1
  90. package/dist/esm/src/utils/protocols.js +27 -0
  91. package/dist/esm/src/utils/protocols.js.map +1 -1
  92. package/dist/esm/src/utils/record-limit-occupancy.js +23 -3
  93. package/dist/esm/src/utils/record-limit-occupancy.js.map +1 -1
  94. package/dist/esm/src/utils/records.js +29 -0
  95. package/dist/esm/src/utils/records.js.map +1 -1
  96. package/dist/esm/src/utils/secp256k1.js +12 -11
  97. package/dist/esm/src/utils/secp256k1.js.map +1 -1
  98. package/dist/esm/src/utils/secp256r1.js +12 -20
  99. package/dist/esm/src/utils/secp256r1.js.map +1 -1
  100. package/dist/esm/src/utils/time.js +103 -25
  101. package/dist/esm/src/utils/time.js.map +1 -1
  102. package/dist/esm/tests/core/constants.spec.js +35 -0
  103. package/dist/esm/tests/core/constants.spec.js.map +1 -0
  104. package/dist/esm/tests/core/encryption-control.spec.js +100 -0
  105. package/dist/esm/tests/core/encryption-control.spec.js.map +1 -0
  106. package/dist/esm/tests/core/message.spec.js +35 -0
  107. package/dist/esm/tests/core/message.spec.js.map +1 -1
  108. package/dist/esm/tests/core/protocol-authorization.spec.js +1 -1
  109. package/dist/esm/tests/core/protocol-authorization.spec.js.map +1 -1
  110. package/dist/esm/tests/core/replication-apply.spec.js +157 -74
  111. package/dist/esm/tests/core/replication-apply.spec.js.map +1 -1
  112. package/dist/esm/tests/core/replication-replay-property.spec.js +2 -1
  113. package/dist/esm/tests/core/replication-replay-property.spec.js.map +1 -1
  114. package/dist/esm/tests/core/validation-read-closure.spec.js +14 -28
  115. package/dist/esm/tests/core/validation-read-closure.spec.js.map +1 -1
  116. package/dist/esm/tests/core/validation-state-reader.spec.js +19 -23
  117. package/dist/esm/tests/core/validation-state-reader.spec.js.map +1 -1
  118. package/dist/esm/tests/dwn.spec.js +2 -1
  119. package/dist/esm/tests/dwn.spec.js.map +1 -1
  120. package/dist/esm/tests/event-emitter-wake-publisher.spec.js +51 -0
  121. package/dist/esm/tests/event-emitter-wake-publisher.spec.js.map +1 -0
  122. package/dist/esm/tests/features/protocol-composition.spec.js +1 -1
  123. package/dist/esm/tests/features/protocol-composition.spec.js.map +1 -1
  124. package/dist/esm/tests/features/records-record-limit.spec.js +1 -1
  125. package/dist/esm/tests/features/records-record-limit.spec.js.map +1 -1
  126. package/dist/esm/tests/fuzz/encryption.fuzz.spec.js +9 -1
  127. package/dist/esm/tests/fuzz/encryption.fuzz.spec.js.map +1 -1
  128. package/dist/esm/tests/fuzz/process-message.fuzz.spec.js +1 -1
  129. package/dist/esm/tests/fuzz/process-message.fuzz.spec.js.map +1 -1
  130. package/dist/esm/tests/fuzz/protocols-utils.fuzz.spec.js +29 -1
  131. package/dist/esm/tests/fuzz/protocols-utils.fuzz.spec.js.map +1 -1
  132. package/dist/esm/tests/fuzz/secp256k1.fuzz.spec.js +2 -2
  133. package/dist/esm/tests/fuzz/secp256k1.fuzz.spec.js.map +1 -1
  134. package/dist/esm/tests/fuzz/time.fuzz.spec.js +7 -1
  135. package/dist/esm/tests/fuzz/time.fuzz.spec.js.map +1 -1
  136. package/dist/esm/tests/handlers/messages-query.spec.js +123 -11
  137. package/dist/esm/tests/handlers/messages-query.spec.js.map +1 -1
  138. package/dist/esm/tests/handlers/messages-read.spec.js +95 -0
  139. package/dist/esm/tests/handlers/messages-read.spec.js.map +1 -1
  140. package/dist/esm/tests/handlers/messages-subscribe.spec.js +90 -0
  141. package/dist/esm/tests/handlers/messages-subscribe.spec.js.map +1 -1
  142. package/dist/esm/tests/handlers/protocols-configure.spec.js +66 -0
  143. package/dist/esm/tests/handlers/protocols-configure.spec.js.map +1 -1
  144. package/dist/esm/tests/handlers/records-count.spec.js +370 -0
  145. package/dist/esm/tests/handlers/records-count.spec.js.map +1 -1
  146. package/dist/esm/tests/handlers/records-delete.spec.js +70 -1
  147. package/dist/esm/tests/handlers/records-delete.spec.js.map +1 -1
  148. package/dist/esm/tests/handlers/records-query.spec.js +562 -1
  149. package/dist/esm/tests/handlers/records-query.spec.js.map +1 -1
  150. package/dist/esm/tests/handlers/records-read.spec.js +140 -2
  151. package/dist/esm/tests/handlers/records-read.spec.js.map +1 -1
  152. package/dist/esm/tests/handlers/records-subscribe.spec.js +241 -1
  153. package/dist/esm/tests/handlers/records-subscribe.spec.js.map +1 -1
  154. package/dist/esm/tests/handlers/records-write.spec.js +1187 -29
  155. package/dist/esm/tests/handlers/records-write.spec.js.map +1 -1
  156. package/dist/esm/tests/interfaces/protocols-configure.spec.js +290 -2
  157. package/dist/esm/tests/interfaces/protocols-configure.spec.js.map +1 -1
  158. package/dist/esm/tests/interfaces/records-write.spec.js +47 -5
  159. package/dist/esm/tests/interfaces/records-write.spec.js.map +1 -1
  160. package/dist/esm/tests/protocols/encryption.spec.js +187 -452
  161. package/dist/esm/tests/protocols/encryption.spec.js.map +1 -1
  162. package/dist/esm/tests/scenarios/end-to-end-tests.spec.js +13 -27
  163. package/dist/esm/tests/scenarios/end-to-end-tests.spec.js.map +1 -1
  164. package/dist/esm/tests/store/blockstore-level.spec.js +33 -10
  165. package/dist/esm/tests/store/blockstore-level.spec.js.map +1 -1
  166. package/dist/esm/tests/store/blockstore-mock.spec.js +31 -7
  167. package/dist/esm/tests/store/blockstore-mock.spec.js.map +1 -1
  168. package/dist/esm/tests/store/blockstore-utils.spec.js +115 -0
  169. package/dist/esm/tests/store/blockstore-utils.spec.js.map +1 -0
  170. package/dist/esm/tests/store/index-level.spec.js +3 -3
  171. package/dist/esm/tests/store/index-level.spec.js.map +1 -1
  172. package/dist/esm/tests/test-stores.js +2 -1
  173. package/dist/esm/tests/test-stores.js.map +1 -1
  174. package/dist/esm/tests/utils/cid.spec.js +15 -0
  175. package/dist/esm/tests/utils/cid.spec.js.map +1 -1
  176. package/dist/esm/tests/utils/data-stream.spec.js +30 -0
  177. package/dist/esm/tests/utils/data-stream.spec.js.map +1 -1
  178. package/dist/esm/tests/utils/encryption-control-test-utils.js +111 -0
  179. package/dist/esm/tests/utils/encryption-control-test-utils.js.map +1 -0
  180. package/dist/esm/tests/utils/encryption.spec.js +198 -5
  181. package/dist/esm/tests/utils/encryption.spec.js.map +1 -1
  182. package/dist/esm/tests/utils/grant-key-coverage.spec.js +262 -0
  183. package/dist/esm/tests/utils/grant-key-coverage.spec.js.map +1 -0
  184. package/dist/esm/tests/utils/memory-cache.spec.js +12 -0
  185. package/dist/esm/tests/utils/memory-cache.spec.js.map +1 -1
  186. package/dist/esm/tests/utils/secp256r1.spec.js +2 -2
  187. package/dist/esm/tests/utils/secp256r1.spec.js.map +1 -1
  188. package/dist/esm/tests/utils/test-data-generator.js +2 -1
  189. package/dist/esm/tests/utils/test-data-generator.js.map +1 -1
  190. package/dist/esm/tests/utils/test-validation-state-reader.js +1 -1
  191. package/dist/esm/tests/utils/test-validation-state-reader.js.map +1 -1
  192. package/dist/esm/tests/utils/time.spec.js +26 -0
  193. package/dist/esm/tests/utils/time.spec.js.map +1 -1
  194. package/dist/esm/tests/validation/json-schemas/encryption/audience.spec.js +45 -0
  195. package/dist/esm/tests/validation/json-schemas/encryption/audience.spec.js.map +1 -0
  196. package/dist/esm/tests/validation/json-schemas/encryption/delivery.spec.js +47 -0
  197. package/dist/esm/tests/validation/json-schemas/encryption/delivery.spec.js.map +1 -0
  198. package/dist/esm/tests/validation/json-schemas/encryption/wrapped-grant-key-envelope.spec.js +43 -0
  199. package/dist/esm/tests/validation/json-schemas/encryption/wrapped-grant-key-envelope.spec.js.map +1 -0
  200. package/dist/esm/tests/validation/json-schemas/protocols/protocols-configure.spec.js +152 -0
  201. package/dist/esm/tests/validation/json-schemas/protocols/protocols-configure.spec.js.map +1 -1
  202. package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js +46 -1
  203. package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js.map +1 -1
  204. package/dist/types/generated/precompiled-validators.d.ts +20 -4
  205. package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
  206. package/dist/types/src/core/constants.d.ts +39 -0
  207. package/dist/types/src/core/constants.d.ts.map +1 -1
  208. package/dist/types/src/core/dwn-error.d.ts +29 -11
  209. package/dist/types/src/core/dwn-error.d.ts.map +1 -1
  210. package/dist/types/src/core/encryption-control.d.ts +128 -0
  211. package/dist/types/src/core/encryption-control.d.ts.map +1 -0
  212. package/dist/types/src/core/message.d.ts +4 -0
  213. package/dist/types/src/core/message.d.ts.map +1 -1
  214. package/dist/types/src/core/messages-grant-authorization.d.ts +11 -0
  215. package/dist/types/src/core/messages-grant-authorization.d.ts.map +1 -1
  216. package/dist/types/src/core/protocol-authorization-action.d.ts.map +1 -1
  217. package/dist/types/src/core/protocol-authorization-validation.d.ts.map +1 -1
  218. package/dist/types/src/core/protocol-authorization.d.ts.map +1 -1
  219. package/dist/types/src/core/recording-validation-state-reader.d.ts +2 -3
  220. package/dist/types/src/core/recording-validation-state-reader.d.ts.map +1 -1
  221. package/dist/types/src/core/replication-apply.d.ts +10 -1
  222. package/dist/types/src/core/replication-apply.d.ts.map +1 -1
  223. package/dist/types/src/core/validation-state-reader.d.ts +2 -3
  224. package/dist/types/src/core/validation-state-reader.d.ts.map +1 -1
  225. package/dist/types/src/dwn.d.ts.map +1 -1
  226. package/dist/types/src/event-stream/event-emitter-wake-publisher.d.ts +1 -1
  227. package/dist/types/src/event-stream/event-emitter-wake-publisher.d.ts.map +1 -1
  228. package/dist/types/src/handlers/messages-query.d.ts.map +1 -1
  229. package/dist/types/src/handlers/messages-read.d.ts.map +1 -1
  230. package/dist/types/src/handlers/messages-subscribe.d.ts.map +1 -1
  231. package/dist/types/src/handlers/protocols-configure.d.ts +1 -0
  232. package/dist/types/src/handlers/protocols-configure.d.ts.map +1 -1
  233. package/dist/types/src/handlers/records-count.d.ts +2 -0
  234. package/dist/types/src/handlers/records-count.d.ts.map +1 -1
  235. package/dist/types/src/handlers/records-delete.d.ts.map +1 -1
  236. package/dist/types/src/handlers/records-query.d.ts +3 -0
  237. package/dist/types/src/handlers/records-query.d.ts.map +1 -1
  238. package/dist/types/src/handlers/records-read.d.ts.map +1 -1
  239. package/dist/types/src/handlers/records-subscribe.d.ts +2 -0
  240. package/dist/types/src/handlers/records-subscribe.d.ts.map +1 -1
  241. package/dist/types/src/handlers/records-write.d.ts.map +1 -1
  242. package/dist/types/src/index.d.ts +12 -18
  243. package/dist/types/src/index.d.ts.map +1 -1
  244. package/dist/types/src/interfaces/protocols-configure.d.ts +13 -1
  245. package/dist/types/src/interfaces/protocols-configure.d.ts.map +1 -1
  246. package/dist/types/src/interfaces/records-write.d.ts +5 -1
  247. package/dist/types/src/interfaces/records-write.d.ts.map +1 -1
  248. package/dist/types/src/jose/algorithms/signing/ed25519.d.ts.map +1 -1
  249. package/dist/types/src/protocols/encryption.d.ts +15 -19
  250. package/dist/types/src/protocols/encryption.d.ts.map +1 -1
  251. package/dist/types/src/store/blockstore-level.d.ts +11 -11
  252. package/dist/types/src/store/blockstore-level.d.ts.map +1 -1
  253. package/dist/types/src/store/blockstore-mock.d.ts +12 -12
  254. package/dist/types/src/store/blockstore-mock.d.ts.map +1 -1
  255. package/dist/types/src/store/blockstore-utils.d.ts +23 -0
  256. package/dist/types/src/store/blockstore-utils.d.ts.map +1 -0
  257. package/dist/types/src/store/blockstore.d.ts +3 -0
  258. package/dist/types/src/store/blockstore.d.ts.map +1 -0
  259. package/dist/types/src/store/data-store-level.d.ts.map +1 -1
  260. package/dist/types/src/store/level.d.ts +13 -0
  261. package/dist/types/src/store/level.d.ts.map +1 -0
  262. package/dist/types/src/types/cache.d.ts +2 -2
  263. package/dist/types/src/types/cache.d.ts.map +1 -1
  264. package/dist/types/src/types/encryption-types.d.ts +31 -2
  265. package/dist/types/src/types/encryption-types.d.ts.map +1 -1
  266. package/dist/types/src/types/validation-state-reader.d.ts +3 -5
  267. package/dist/types/src/types/validation-state-reader.d.ts.map +1 -1
  268. package/dist/types/src/utils/data-stream.d.ts +5 -0
  269. package/dist/types/src/utils/data-stream.d.ts.map +1 -1
  270. package/dist/types/src/utils/encryption.d.ts +53 -24
  271. package/dist/types/src/utils/encryption.d.ts.map +1 -1
  272. package/dist/types/src/utils/grant-key-coverage.d.ts +36 -0
  273. package/dist/types/src/utils/grant-key-coverage.d.ts.map +1 -0
  274. package/dist/types/src/utils/hd-key.d.ts.map +1 -1
  275. package/dist/types/src/utils/jws.d.ts.map +1 -1
  276. package/dist/types/src/utils/memory-cache.d.ts +4 -2
  277. package/dist/types/src/utils/memory-cache.d.ts.map +1 -1
  278. package/dist/types/src/utils/protocols.d.ts +11 -0
  279. package/dist/types/src/utils/protocols.d.ts.map +1 -1
  280. package/dist/types/src/utils/record-limit-occupancy.d.ts +7 -0
  281. package/dist/types/src/utils/record-limit-occupancy.d.ts.map +1 -1
  282. package/dist/types/src/utils/records.d.ts +2 -0
  283. package/dist/types/src/utils/records.d.ts.map +1 -1
  284. package/dist/types/src/utils/secp256k1.d.ts.map +1 -1
  285. package/dist/types/src/utils/secp256r1.d.ts.map +1 -1
  286. package/dist/types/src/utils/time.d.ts +21 -13
  287. package/dist/types/src/utils/time.d.ts.map +1 -1
  288. package/dist/types/tests/core/constants.spec.d.ts +2 -0
  289. package/dist/types/tests/core/constants.spec.d.ts.map +1 -0
  290. package/dist/types/tests/core/encryption-control.spec.d.ts +2 -0
  291. package/dist/types/tests/core/encryption-control.spec.d.ts.map +1 -0
  292. package/dist/types/tests/dwn.spec.d.ts.map +1 -1
  293. package/dist/types/tests/event-emitter-wake-publisher.spec.d.ts +2 -0
  294. package/dist/types/tests/event-emitter-wake-publisher.spec.d.ts.map +1 -0
  295. package/dist/types/tests/handlers/messages-query.spec.d.ts.map +1 -1
  296. package/dist/types/tests/handlers/messages-read.spec.d.ts.map +1 -1
  297. package/dist/types/tests/handlers/messages-subscribe.spec.d.ts.map +1 -1
  298. package/dist/types/tests/handlers/protocols-configure.spec.d.ts.map +1 -1
  299. package/dist/types/tests/handlers/records-count.spec.d.ts.map +1 -1
  300. package/dist/types/tests/handlers/records-delete.spec.d.ts.map +1 -1
  301. package/dist/types/tests/handlers/records-query.spec.d.ts.map +1 -1
  302. package/dist/types/tests/handlers/records-read.spec.d.ts.map +1 -1
  303. package/dist/types/tests/handlers/records-subscribe.spec.d.ts.map +1 -1
  304. package/dist/types/tests/handlers/records-write.spec.d.ts.map +1 -1
  305. package/dist/types/tests/scenarios/end-to-end-tests.spec.d.ts.map +1 -1
  306. package/dist/types/tests/store/blockstore-utils.spec.d.ts +2 -0
  307. package/dist/types/tests/store/blockstore-utils.spec.d.ts.map +1 -0
  308. package/dist/types/tests/test-stores.d.ts.map +1 -1
  309. package/dist/types/tests/utils/encryption-control-test-utils.d.ts +46 -0
  310. package/dist/types/tests/utils/encryption-control-test-utils.d.ts.map +1 -0
  311. package/dist/types/tests/utils/grant-key-coverage.spec.d.ts +2 -0
  312. package/dist/types/tests/utils/grant-key-coverage.spec.d.ts.map +1 -0
  313. package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -1
  314. package/dist/types/tests/validation/json-schemas/encryption/audience.spec.d.ts +2 -0
  315. package/dist/types/tests/validation/json-schemas/encryption/audience.spec.d.ts.map +1 -0
  316. package/dist/types/tests/validation/json-schemas/encryption/delivery.spec.d.ts +2 -0
  317. package/dist/types/tests/validation/json-schemas/encryption/delivery.spec.d.ts.map +1 -0
  318. package/dist/types/tests/validation/json-schemas/encryption/wrapped-grant-key-envelope.spec.d.ts +2 -0
  319. package/dist/types/tests/validation/json-schemas/encryption/wrapped-grant-key-envelope.spec.d.ts.map +1 -0
  320. package/package.json +47 -28
  321. package/src/core/constants.ts +61 -0
  322. package/src/core/dwn-error.ts +29 -11
  323. package/src/core/encryption-control.ts +1249 -0
  324. package/src/core/message.ts +7 -0
  325. package/src/core/messages-grant-authorization.ts +60 -9
  326. package/src/core/protocol-authorization-action.ts +3 -13
  327. package/src/core/protocol-authorization-validation.ts +66 -46
  328. package/src/core/protocol-authorization.ts +7 -0
  329. package/src/core/recording-validation-state-reader.ts +4 -5
  330. package/src/core/replication-apply.ts +77 -133
  331. package/src/core/validation-state-reader.ts +6 -8
  332. package/src/dwn.ts +1 -2
  333. package/src/event-stream/event-emitter-wake-publisher.ts +10 -14
  334. package/src/handlers/messages-query.ts +6 -22
  335. package/src/handlers/messages-read.ts +4 -3
  336. package/src/handlers/messages-subscribe.ts +34 -30
  337. package/src/handlers/protocols-configure.ts +7 -4
  338. package/src/handlers/records-count.ts +111 -10
  339. package/src/handlers/records-delete.ts +15 -0
  340. package/src/handlers/records-query.ts +176 -20
  341. package/src/handlers/records-read.ts +19 -6
  342. package/src/handlers/records-subscribe.ts +158 -8
  343. package/src/handlers/records-write.ts +19 -0
  344. package/src/index.ts +50 -22
  345. package/src/interfaces/protocols-configure.ts +102 -11
  346. package/src/interfaces/records-write.ts +49 -43
  347. package/src/jose/algorithms/signing/ed25519.ts +7 -6
  348. package/src/jose/jws/general/verifier.ts +3 -3
  349. package/src/protocols/encryption.ts +94 -411
  350. package/src/store/blockstore-level.ts +33 -37
  351. package/src/store/blockstore-mock.ts +24 -38
  352. package/src/store/blockstore-utils.ts +85 -0
  353. package/src/store/blockstore.ts +8 -0
  354. package/src/store/data-store-level.ts +5 -12
  355. package/src/store/level.ts +19 -0
  356. package/src/types/cache.ts +3 -3
  357. package/src/types/encryption-types.ts +39 -2
  358. package/src/types/validation-state-reader.ts +3 -5
  359. package/src/utils/data-stream.ts +29 -1
  360. package/src/utils/encryption.ts +190 -60
  361. package/src/utils/grant-key-coverage.ts +303 -0
  362. package/src/utils/hd-key.ts +1 -2
  363. package/src/utils/jws.ts +8 -2
  364. package/src/utils/memory-cache.ts +42 -11
  365. package/src/utils/protocols.ts +32 -0
  366. package/src/utils/record-limit-occupancy.ts +34 -5
  367. package/src/utils/records.ts +36 -2
  368. package/src/utils/secp256k1.ts +12 -12
  369. package/src/utils/secp256r1.ts +12 -22
  370. package/src/utils/time.ts +145 -27
  371. package/dist/esm/tests/validation/json-schemas/encryption/audience-key.spec.js +0 -40
  372. package/dist/esm/tests/validation/json-schemas/encryption/audience-key.spec.js.map +0 -1
  373. package/dist/types/tests/validation/json-schemas/encryption/audience-key.spec.d.ts +0 -2
  374. package/dist/types/tests/validation/json-schemas/encryption/audience-key.spec.d.ts.map +0 -1
  375. package/src/types/mitt.d.ts +0 -28
@@ -1,7 +1,6 @@
1
1
  import type { PrivateKeyJwk, PublicKeyJwk } from '../types/jose-types.js';
2
2
 
3
3
  import { Encoder } from './encoder.js';
4
- import { getWebcryptoSubtle } from '@noble/ciphers/webcrypto';
5
4
  import { X25519 } from '@enbox/crypto';
6
5
  import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
7
6
 
@@ -82,7 +81,7 @@ export class HdKey {
82
81
  }): Promise<Uint8Array> {
83
82
  const { hashAlgorithm, initialKeyMaterial, info, keyLengthInBytes } = params;
84
83
 
85
- const webCrypto = getWebcryptoSubtle() as SubtleCrypto;
84
+ const webCrypto = globalThis.crypto.subtle;
86
85
 
87
86
  // Import the `initialKeyMaterial` into the Web Crypto API to use for the key derivation operation.
88
87
  const webCryptoKey = await webCrypto.importKey('raw', initialKeyMaterial as BufferSource, { name: 'HKDF' }, false, ['deriveBits']);
package/src/utils/jws.ts CHANGED
@@ -3,13 +3,19 @@ import type { MessageSigner } from '../types/signer.js';
3
3
  import type { SignatureEntry } from '../types/jws-types.js';
4
4
  import type { KeyMaterial, PublicKeyJwk } from '../types/jose-types.js';
5
5
 
6
- import isPlainObject from 'lodash/isPlainObject.js';
7
-
8
6
  import { Encoder } from './encoder.js';
9
7
  import { PrivateKeySigner } from './private-key-signer.js';
10
8
  import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
11
9
  import { signatureAlgorithms, type SupportedCurve } from '../jose/algorithms/signing/signature-algorithms.js';
12
10
 
11
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
12
+ if (typeof value !== 'object' || value === null) {
13
+ return false;
14
+ }
15
+
16
+ const prototype = Object.getPrototypeOf(value);
17
+ return prototype === Object.prototype || prototype === null;
18
+ }
13
19
 
14
20
  /**
15
21
  * Utility class for JWS related operations.
@@ -1,31 +1,62 @@
1
1
  import type { Cache } from '../types/cache.js';
2
- import { LRUCache } from 'lru-cache';
2
+
3
+ type CacheEntry = {
4
+ expiresAt: number;
5
+ value: unknown;
6
+ };
3
7
 
4
8
  /**
5
9
  * A cache using local memory.
6
10
  */
7
11
  export class MemoryCache implements Cache {
8
- private readonly cache: LRUCache<string, any>;
12
+ private static readonly maxEntries = 100_000;
13
+
14
+ private readonly cache = new Map<string, CacheEntry>();
9
15
 
10
16
  /**
11
17
  * @param timeToLiveInSeconds time-to-live for every key-value pair set in the cache
12
18
  */
13
- public constructor (private readonly timeToLiveInSeconds: number) {
14
- this.cache = new LRUCache({
15
- max : 100_000,
16
- ttl : timeToLiveInSeconds * 1000
17
- });
19
+ public constructor(private readonly timeToLiveInSeconds: number) {
18
20
  }
19
21
 
20
- async set(key: string, value: any): Promise<void> {
22
+ public async set<T = unknown>(key: string, value: T): Promise<void> {
21
23
  try {
22
- this.cache.set(key, value);
24
+ const entry = {
25
+ expiresAt : Date.now() + this.timeToLiveInSeconds * 1000,
26
+ value : value,
27
+ };
28
+
29
+ this.cache.delete(key);
30
+ this.cache.set(key, entry);
31
+ this.evictOldestEntries();
23
32
  } catch {
24
33
  // let the code continue as this is a non-fatal error
25
34
  }
26
35
  }
27
36
 
28
- async get(key: string): Promise<any | undefined> {
29
- return this.cache.get(key);
37
+ public async get<T = unknown>(key: string): Promise<T | undefined> {
38
+ const entry = this.cache.get(key);
39
+ if (entry === undefined) {
40
+ return undefined;
41
+ }
42
+
43
+ if (Date.now() >= entry.expiresAt) {
44
+ this.cache.delete(key);
45
+ return undefined;
46
+ }
47
+
48
+ this.cache.delete(key);
49
+ this.cache.set(key, entry);
50
+ return entry.value as T;
51
+ }
52
+
53
+ private evictOldestEntries(): void {
54
+ while (this.cache.size > MemoryCache.maxEntries) {
55
+ const oldestKey = this.cache.keys().next().value;
56
+ if (oldestKey === undefined) {
57
+ return;
58
+ }
59
+ this.cache.delete(oldestKey);
60
+ }
30
61
  }
31
62
  }
@@ -52,6 +52,38 @@ export function getTypeName(protocolPath: string): string {
52
52
  return protocolPath.split('/').slice(-1)[0];
53
53
  }
54
54
 
55
+ /**
56
+ * Computes the role-audience context id for a role path relative to a source record context id.
57
+ * Root-level role audiences use the empty string; nested role audiences use the ancestor
58
+ * context prefix at the same depth as the role parent.
59
+ */
60
+ export function getRoleAudienceContextId(rolePath: string, contextId?: string): string | undefined {
61
+ const roleParentDepth = rolePath.split('/').length - 1;
62
+ if (roleParentDepth === 0) {
63
+ return '';
64
+ }
65
+
66
+ if (contextId === undefined) {
67
+ return undefined;
68
+ }
69
+
70
+ const contextSegments = contextId.split('/');
71
+ if (contextSegments.length < roleParentDepth) {
72
+ return undefined;
73
+ }
74
+
75
+ return contextSegments.slice(0, roleParentDepth).join('/');
76
+ }
77
+
78
+ /**
79
+ * Computes the context prefix used when querying for role records. Root-level
80
+ * role records are queried without a context prefix.
81
+ */
82
+ export function getRoleContextPrefix(rolePath: string, contextId?: string): string | undefined {
83
+ const roleAudienceContextId = getRoleAudienceContextId(rolePath, contextId);
84
+ return roleAudienceContextId === '' ? undefined : roleAudienceContextId;
85
+ }
86
+
55
87
  /**
56
88
  * Gets the rule set at a given protocol path within a protocol definition's structure tree.
57
89
  * Returns `undefined` if the path does not exist.
@@ -37,6 +37,13 @@ type RecordLimitFilterResolution = {
37
37
  projectedFilters: Filter[];
38
38
  };
39
39
 
40
+ type OccupancyProjectionInput<T extends RecordsWriteMessage> = {
41
+ records: T[];
42
+ max: number;
43
+ getScopeKey(record: T): string;
44
+ compareRecords(left: T, right: T): number;
45
+ };
46
+
40
47
  /**
41
48
  * Queries records with bounded `$recordLimit` occupancy projection when every limited filter targets one concrete scope.
42
49
  *
@@ -285,11 +292,12 @@ async function findOccupantRecordIds(input: {
285
292
  ...boundaryCandidates,
286
293
  ];
287
294
 
288
- return new Set(
289
- rankedCandidates
290
- .slice(0, input.recordLimit.max)
291
- .map((message): string => message.recordId)
292
- );
295
+ return selectOccupantRecordIds({
296
+ records : rankedCandidates,
297
+ max : input.recordLimit.max,
298
+ getScopeKey : (): string => '',
299
+ compareRecords : compareRecordLimitCandidates,
300
+ });
293
301
  }
294
302
 
295
303
  function buildRecordLimitScopeFilter(scope: RecordLimitScope): Filter {
@@ -375,3 +383,24 @@ function compareRecordLimitCandidates(left: RecordsWriteMessage, right: RecordsW
375
383
 
376
384
  return lexicographicalCompare(left.recordId, right.recordId);
377
385
  }
386
+
387
+ export function selectOccupantRecordIds<T extends RecordsWriteMessage>(input: OccupancyProjectionInput<T>): Set<string> {
388
+ const occupants = new Set<string>();
389
+ const groups = new Map<string, T[]>();
390
+
391
+ for (const record of input.records) {
392
+ const scopeKey = input.getScopeKey(record);
393
+ const group = groups.get(scopeKey) ?? [];
394
+ group.push(record);
395
+ groups.set(scopeKey, group);
396
+ }
397
+
398
+ for (const group of groups.values()) {
399
+ group.sort(input.compareRecords);
400
+ for (const record of group.slice(0, input.max)) {
401
+ occupants.add(record.recordId);
402
+ }
403
+ }
404
+
405
+ return occupants;
406
+ }
@@ -1,8 +1,8 @@
1
1
  import type { DerivedPrivateJwk } from './hd-key.js';
2
2
  import type { Jwk } from '@enbox/crypto';
3
3
  import type { KeyDecrypter } from '../types/encryption-types.js';
4
- import type { KeyEncryption } from './encryption.js';
5
4
  import type { PublicKeyJwk } from '../types/jose-types.js';
5
+ import type { X25519KeyEncryption } from './encryption.js';
6
6
  import type { Filter, KeyValues, StartsWithFilter } from '../types/query-types.js';
7
7
  import type { GenericMessage, GenericSignaturePayload, MessageSort } from '../types/message-types.js';
8
8
  import type { RecordsCountMessage, RecordsDeleteMessage, RecordsFilter, RecordsQueryMessage, RecordsReadMessage, RecordsSubscribeMessage, RecordsWriteDescriptor, RecordsWriteMessage, RecordsWriteTags, RecordsWriteTagsFilter } from '../types/records-types.js';
@@ -21,6 +21,7 @@ import { X25519 } from '@enbox/crypto';
21
21
  import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
22
22
  import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
23
23
  import { Encryption, ROLE_AUDIENCE_DERIVATION_SCHEME } from './encryption.js';
24
+ import { ENCRYPTION_CONTROL_PATHS, isEncryptionControlPath } from '../core/constants.js';
24
25
  import { HdKey, KeyDerivationScheme } from './hd-key.js';
25
26
  import { normalizeProtocolUrl, normalizeSchemaUrl } from './url.js';
26
27
 
@@ -132,7 +133,7 @@ export class Records {
132
133
  private static async findMatchingKeyEncryption(
133
134
  recordsWrite: RecordsWriteMessage,
134
135
  keyOrDecrypter: DerivedPrivateJwk | KeyDecrypter,
135
- ): Promise<{ fullDerivationPath: string[]; leafPrivateKey?: Jwk; matchingKeyEncryption?: KeyEncryption }> {
136
+ ): Promise<{ fullDerivationPath: string[]; leafPrivateKey?: Jwk; matchingKeyEncryption?: X25519KeyEncryption }> {
136
137
  const { encryption } = recordsWrite;
137
138
  const fullDerivationPath = Records.constructKeyDerivationPath(keyOrDecrypter.derivationScheme, recordsWrite);
138
139
 
@@ -334,6 +335,10 @@ export class Records {
334
335
  return;
335
336
  }
336
337
 
338
+ if (isEncryptionControlPath(protocolPath)) {
339
+ return;
340
+ }
341
+
337
342
  const expectedParentDepth = protocolPath.split('/').length - 1;
338
343
  const contextIdSegments = contextId?.split('/');
339
344
  if (
@@ -442,6 +447,35 @@ export class Records {
442
447
  return filterCopy;
443
448
  }
444
449
 
450
+ public static buildUnpublishedControlRecordsFilter(filter: RecordsFilter, dateSort?: DateSort): Filter {
451
+ return {
452
+ ...Records.convertFilter(filter, dateSort),
453
+ interface : DwnInterfaceName.Records,
454
+ method : DwnMethodName.Write,
455
+ isLatestBaseState : true,
456
+ published : false,
457
+ };
458
+ }
459
+
460
+ public static buildControlRecordsFilters(filters: Filter[]): Filter[] {
461
+ const controlFilters: Filter[] = [];
462
+ for (const filter of filters) {
463
+ const protocolPath = filter.protocolPath;
464
+ if (typeof protocolPath === 'string') {
465
+ if (isEncryptionControlPath(protocolPath)) {
466
+ controlFilters.push(filter);
467
+ }
468
+ continue;
469
+ }
470
+
471
+ for (const controlPath of ENCRYPTION_CONTROL_PATHS) {
472
+ controlFilters.push({ ...filter, protocolPath: controlPath });
473
+ }
474
+ }
475
+
476
+ return controlFilters;
477
+ }
478
+
445
479
  /**
446
480
  * Validates the referential integrity of both author-delegated grant and owner-delegated grant.
447
481
  * @param authorSignaturePayload Decoded payload of the author signature of the message. Pass `undefined` if message is not signed.
@@ -1,7 +1,8 @@
1
1
  import type { JwkParamsEcPrivate, JwkParamsEcPublic } from '@enbox/crypto';
2
2
  import type { PrivateKeyJwk, PublicKeyJwk } from '../types/jose-types.js';
3
3
 
4
- import * as secp256k1 from '@noble/secp256k1';
4
+ import { bytesToNumberBE } from '@noble/curves/utils.js';
5
+ import { secp256k1 } from '@noble/curves/secp256k1.js';
5
6
 
6
7
  import { Encoder } from '../utils/encoder.js';
7
8
  import { sha256 } from 'multiformats/hashes/sha2';
@@ -30,8 +31,8 @@ export class Secp256k1 {
30
31
  let uncompressedPublicKeyBytes;
31
32
  if (publicKeyBytes.byteLength === 33) {
32
33
  // this means given key is compressed
33
- const curvePoints = secp256k1.ProjectivePoint.fromHex(publicKeyBytes);
34
- uncompressedPublicKeyBytes = curvePoints.toRawBytes(false); // isCompressed = false
34
+ const curvePoints = secp256k1.Point.fromBytes(publicKeyBytes);
35
+ uncompressedPublicKeyBytes = curvePoints.toBytes(false); // isCompressed = false
35
36
  } else {
36
37
  uncompressedPublicKeyBytes = publicKeyBytes;
37
38
  }
@@ -75,10 +76,10 @@ export class Secp256k1 {
75
76
  const x = Encoder.base64UrlToBytes(ecJwk.x);
76
77
  const y = Encoder.base64UrlToBytes(ecJwk.y!);
77
78
 
78
- return secp256k1.ProjectivePoint.fromAffine({
79
- x : secp256k1.etc.bytesToNumberBE(x),
80
- y : secp256k1.etc.bytesToNumberBE(y)
81
- }).toRawBytes(true);
79
+ return secp256k1.Point.fromAffine({
80
+ x : bytesToNumberBE(x),
81
+ y : bytesToNumberBE(y)
82
+ }).toBytes(true);
82
83
  }
83
84
 
84
85
  /**
@@ -100,7 +101,7 @@ export class Secp256k1 {
100
101
  const hashedContent = await sha256.encode(content);
101
102
  const privateKeyBytes = Secp256k1.privateJwkToBytes(privateJwk);
102
103
 
103
- return (await secp256k1.signAsync(hashedContent, privateKeyBytes)).toCompactRawBytes();
104
+ return secp256k1.sign(hashedContent, privateKeyBytes, { prehash: false });
104
105
  }
105
106
 
106
107
  /**
@@ -112,14 +113,14 @@ export class Secp256k1 {
112
113
 
113
114
  const publicKeyBytes = Secp256k1.publicJwkToBytes(publicJwk);
114
115
  const hashedContent = await sha256.encode(content);
115
- return secp256k1.verify(signature, hashedContent, publicKeyBytes, { lowS: false });
116
+ return secp256k1.verify(signature, hashedContent, publicKeyBytes, { lowS: false, prehash: false });
116
117
  }
117
118
 
118
119
  /**
119
120
  * Generates a random key pair in JWK format.
120
121
  */
121
122
  public static async generateKeyPair(): Promise<{publicJwk: PublicKeyJwk, privateJwk: PrivateKeyJwk}> {
122
- const privateKeyBytes = secp256k1.utils.randomPrivateKey();
123
+ const privateKeyBytes = secp256k1.utils.randomSecretKey();
123
124
  const publicKeyBytes = secp256k1.getPublicKey(privateKeyBytes, false); // `false` = uncompressed
124
125
 
125
126
  const d = Encoder.bytesToBase64Url(privateKeyBytes);
@@ -133,7 +134,7 @@ export class Secp256k1 {
133
134
  * Generates key pair in raw bytes, where the `publicKey` is compressed.
134
135
  */
135
136
  public static async generateKeyPairRaw(): Promise<{publicKey: Uint8Array, privateKey: Uint8Array}> {
136
- const privateKey = secp256k1.utils.randomPrivateKey();
137
+ const privateKey = secp256k1.utils.randomSecretKey();
137
138
  const publicKey = secp256k1.getPublicKey(privateKey, true); // `true` = compressed
138
139
 
139
140
  return { publicKey, privateKey };
@@ -156,4 +157,3 @@ export class Secp256k1 {
156
157
  return publicKey as PublicKeyJwk;
157
158
  }
158
159
  }
159
-
@@ -1,14 +1,12 @@
1
1
  import type { JwkParamsEcPrivate, JwkParamsEcPublic } from '@enbox/crypto';
2
2
  import type { PrivateKeyJwk, PublicKeyJwk } from '../types/jose-types.js';
3
3
 
4
- import { p256, secp256r1 } from '@noble/curves/p256';
4
+ import { bytesToNumberBE } from '@noble/curves/utils.js';
5
+ import { p256 } from '@noble/curves/nist.js';
5
6
 
6
7
  import { Encoder } from './encoder.js';
7
8
  import { sha256 } from 'multiformats/hashes/sha2';
8
9
  import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
9
- import { fromString, toString } from 'uint8arrays';
10
-
11
- const u8a = { toString, fromString };
12
10
 
13
11
  /**
14
12
  * Class containing SECP256R1 related utility methods.
@@ -37,8 +35,8 @@ export class Secp256r1 {
37
35
  let uncompressedPublicKeyBytes;
38
36
  if (publicKeyBytes.byteLength === 33) {
39
37
  // this means given key is compressed
40
- const curvePoints = p256.ProjectivePoint.fromHex(publicKeyBytes);
41
- uncompressedPublicKeyBytes = curvePoints.toRawBytes(false); // isCompressed = false
38
+ const curvePoints = p256.Point.fromBytes(publicKeyBytes);
39
+ uncompressedPublicKeyBytes = curvePoints.toBytes(false); // isCompressed = false
42
40
  } else {
43
41
  uncompressedPublicKeyBytes = publicKeyBytes;
44
42
  }
@@ -87,9 +85,7 @@ export class Secp256r1 {
87
85
  const hashedContent = await sha256.encode(content);
88
86
  const privateKeyBytes = Secp256r1.privateJwkToBytes(privateJwk);
89
87
 
90
- return Promise.resolve(
91
- p256.sign(hashedContent, privateKeyBytes).toCompactRawBytes()
92
- );
88
+ return Promise.resolve(p256.sign(hashedContent, privateKeyBytes, { prehash: false }));
93
89
  }
94
90
 
95
91
  /**
@@ -104,21 +100,15 @@ export class Secp256r1 {
104
100
  ): Promise<boolean> {
105
101
  Secp256r1.validateKey(publicJwk);
106
102
 
107
- // handle DER vs compact signature formats
108
- let sig;
109
- if (signature.length === 64) {
110
- sig = p256.Signature.fromCompact(signature);
111
- } else {
112
- sig = p256.Signature.fromDER(signature);
113
- }
103
+ const signatureFormat = signature.length === 64 ? 'compact' : 'der';
114
104
  const hashedContent = await sha256.encode(content);
115
105
  const ecJwk = publicJwk as JwkParamsEcPublic;
116
- const keyBytes = p256.ProjectivePoint.fromAffine({
106
+ const keyBytes = p256.Point.fromAffine({
117
107
  x : Secp256r1.bytesToBigInt(Encoder.base64UrlToBytes(ecJwk.x)),
118
108
  y : Secp256r1.bytesToBigInt(Encoder.base64UrlToBytes(ecJwk.y!)),
119
- }).toRawBytes(false);
109
+ }).toBytes(false);
120
110
 
121
- return p256.verify(sig, hashedContent, keyBytes);
111
+ return p256.verify(signature, hashedContent, keyBytes, { format: signatureFormat, lowS: false, prehash: false });
122
112
  }
123
113
 
124
114
  /**
@@ -128,8 +118,8 @@ export class Secp256r1 {
128
118
  publicJwk: PublicKeyJwk;
129
119
  privateJwk: PrivateKeyJwk;
130
120
  }> {
131
- const privateKeyBytes = p256.utils.randomPrivateKey();
132
- const publicKeyBytes = secp256r1.getPublicKey(privateKeyBytes, false); // `false` = uncompressed
121
+ const privateKeyBytes = p256.utils.randomSecretKey();
122
+ const publicKeyBytes = p256.getPublicKey(privateKeyBytes, false); // `false` = uncompressed
133
123
 
134
124
  const d = Encoder.bytesToBase64Url(privateKeyBytes);
135
125
  const publicJwk: PublicKeyJwk = await Secp256r1.publicKeyToJwk(publicKeyBytes);
@@ -139,6 +129,6 @@ export class Secp256r1 {
139
129
  }
140
130
 
141
131
  public static bytesToBigInt(b: Uint8Array): bigint {
142
- return BigInt(`0x` + u8a.toString(b, 'base16'));
132
+ return bytesToNumberBE(b);
143
133
  }
144
134
  }
package/src/utils/time.ts CHANGED
@@ -1,7 +1,24 @@
1
1
  import { sleep } from '@enbox/common';
2
- import { Temporal } from '@js-temporal/polyfill';
3
2
  import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
4
3
 
4
+ type ParsedTimestamp = {
5
+ epochMilliseconds: number;
6
+ microsecond: number;
7
+ };
8
+
9
+ type TimestampOptions = {
10
+ year?: number;
11
+ month?: number;
12
+ day?: number;
13
+ hour?: number;
14
+ minute?: number;
15
+ second?: number;
16
+ millisecond?: number;
17
+ microsecond?: number;
18
+ };
19
+
20
+ const timestampRegex = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.(\d{6})Z$/;
21
+
5
22
  /**
6
23
  * Time related utilities.
7
24
  */
@@ -19,10 +36,9 @@ export class Time {
19
36
 
20
37
  /**
21
38
  * Returns an UTC ISO-8601 timestamp with microsecond precision accepted by DWN.
22
- * using @js-temporal/polyfill
23
39
  */
24
40
  public static getCurrentTimestamp(): string {
25
- return Temporal.Now.instant().toString({ smallestUnit: 'microseconds' });
41
+ return Time.formatUtcTimestamp(Date.now(), 0);
26
42
  }
27
43
 
28
44
  /**
@@ -30,21 +46,21 @@ export class Time {
30
46
  * @param options - Options for creating the timestamp.
31
47
  * @returns string
32
48
  */
33
- public static createTimestamp(options: {
34
- year?: number, month?: number, day?: number, hour?: number, minute?: number, second?: number, millisecond?: number, microsecond?: number
35
- }): string {
36
- const { year, month, day, hour, minute, second, millisecond, microsecond } = options;
37
- return Temporal.ZonedDateTime.from({
38
- timeZone: 'UTC',
39
- year,
40
- month,
41
- day,
42
- hour,
43
- minute,
44
- second,
45
- millisecond,
46
- microsecond
47
- }).toInstant().toString({ smallestUnit: 'microseconds' });
49
+ public static createTimestamp(options: TimestampOptions): string {
50
+ const year = Time.constrainInteger(Time.requireTimestampField(options.year, 'year'), 0, 9999);
51
+ const month = Time.constrainInteger(Time.requireTimestampField(options.month, 'month'), 1, 12);
52
+ const day = Time.constrainInteger(Time.requireTimestampField(options.day, 'day'), 1, Time.daysInUtcMonth(year, month));
53
+ const hour = Time.constrainInteger(options.hour ?? 0, 0, 23);
54
+ const minute = Time.constrainInteger(options.minute ?? 0, 0, 59);
55
+ const second = Time.constrainInteger(options.second ?? 0, 0, 59);
56
+ const millisecond = Time.constrainInteger(options.millisecond ?? 0, 0, 999);
57
+ const microsecond = Time.constrainInteger(options.microsecond ?? 0, 0, 999);
58
+ const date = new Date(0);
59
+ date.setUTCHours(0, 0, 0, 0);
60
+ date.setUTCFullYear(year, month - 1, day);
61
+ date.setUTCHours(hour, minute, second, millisecond);
62
+
63
+ return Time.formatUtcTimestamp(date.getTime(), microsecond);
48
64
  }
49
65
 
50
66
  /**
@@ -52,22 +68,124 @@ export class Time {
52
68
  * @param offset Negative number means offset into the past.
53
69
  */
54
70
  public static createOffsetTimestamp(offset: { seconds: number }, timestamp?: string): string {
55
- const timestampInstant = timestamp ? Temporal.Instant.from(timestamp) : Temporal.Now.instant();
56
- const offsetDuration = Temporal.Duration.from(offset);
57
- const offsetInstant = timestampInstant.add(offsetDuration);
58
- return offsetInstant.toString({ smallestUnit: 'microseconds' });
71
+ const parsedTimestamp = timestamp === undefined ? { epochMilliseconds: Date.now(), microsecond: 0 } : Time.parseTimestamp(timestamp);
72
+ if (parsedTimestamp === undefined) {
73
+ throw new DwnError(DwnErrorCode.TimestampInvalid, `Invalid timestamp: ${timestamp}`);
74
+ }
75
+
76
+ const offsetSeconds = Time.requireWholeNumber(offset.seconds, 'seconds');
77
+ return Time.formatUtcTimestamp(parsedTimestamp.epochMilliseconds + (offsetSeconds * 1000), parsedTimestamp.microsecond);
59
78
  }
60
79
 
61
80
  /**
62
- * Validates that the provided timestamp is a valid number
81
+ * Validates that the provided timestamp is a DWN-compatible UTC timestamp.
63
82
  * @param timestamp the timestamp to validate
64
- * @throws DwnError if timestamp is not a valid number
83
+ * @throws DwnError if timestamp is invalid
65
84
  */
66
85
  public static validateTimestamp(timestamp: string): void {
67
- try {
68
- Temporal.Instant.from(timestamp);
69
- } catch {
86
+ if (Time.parseTimestamp(timestamp) === undefined) {
70
87
  throw new DwnError(DwnErrorCode.TimestampInvalid, `Invalid timestamp: ${timestamp}`);
71
88
  }
72
89
  }
90
+
91
+ private static constrainInteger(value: number, min: number, max: number): number {
92
+ if (!Number.isFinite(value)) {
93
+ throw new RangeError('timestamp field must be finite');
94
+ }
95
+
96
+ const integer = Math.trunc(value);
97
+ return Math.min(Math.max(integer, min), max);
98
+ }
99
+
100
+ private static daysInUtcMonth(year: number, month: number): number {
101
+ const date = new Date(0);
102
+ date.setUTCHours(0, 0, 0, 0);
103
+ date.setUTCFullYear(year, month, 0);
104
+
105
+ return date.getUTCDate();
106
+ }
107
+
108
+ private static formatUtcTimestamp(epochMilliseconds: number, microsecond: number): string {
109
+ if (!Number.isFinite(epochMilliseconds)) {
110
+ throw new RangeError('timestamp is outside the supported Date range');
111
+ }
112
+
113
+ const date = new Date(epochMilliseconds);
114
+ const year = date.getUTCFullYear();
115
+ if (year < 0 || year > 9999) {
116
+ throw new RangeError('timestamp year must be between 0000 and 9999');
117
+ }
118
+
119
+ const fraction = String((date.getUTCMilliseconds() * 1000) + microsecond).padStart(6, '0');
120
+ return `${Time.pad(year, 4)}-${Time.pad(date.getUTCMonth() + 1, 2)}-${Time.pad(date.getUTCDate(), 2)}` +
121
+ `T${Time.pad(date.getUTCHours(), 2)}:${Time.pad(date.getUTCMinutes(), 2)}:${Time.pad(date.getUTCSeconds(), 2)}.${fraction}Z`;
122
+ }
123
+
124
+ private static pad(value: number, length: number): string {
125
+ return String(value).padStart(length, '0');
126
+ }
127
+
128
+ private static parseTimestamp(timestamp: string): ParsedTimestamp | undefined {
129
+ const match = timestampRegex.exec(timestamp);
130
+ if (match === null) {
131
+ return undefined;
132
+ }
133
+
134
+ const year = Number(match[1]);
135
+ const month = Number(match[2]);
136
+ const day = Number(match[3]);
137
+ const hour = Number(match[4]);
138
+ const minute = Number(match[5]);
139
+ const second = Number(match[6]);
140
+ const fraction = match[7];
141
+ const millisecond = Number(fraction.slice(0, 3));
142
+ const microsecond = Number(fraction.slice(3));
143
+ const isLeapSecond = hour === 23 && minute === 59 && second === 60;
144
+
145
+ if (
146
+ month < 1 ||
147
+ month > 12 ||
148
+ day < 1 ||
149
+ day > Time.daysInUtcMonth(year, month) ||
150
+ hour > 23 ||
151
+ minute > 59 ||
152
+ (second > 59 && !isLeapSecond)
153
+ ) {
154
+ return undefined;
155
+ }
156
+
157
+ const date = new Date(0);
158
+ date.setUTCHours(0, 0, 0, 0);
159
+ date.setUTCFullYear(year, month - 1, day);
160
+ date.setUTCHours(hour, minute, isLeapSecond ? 59 : second, millisecond);
161
+
162
+ if (
163
+ date.getUTCFullYear() !== year ||
164
+ date.getUTCMonth() !== month - 1 ||
165
+ date.getUTCDate() !== day ||
166
+ date.getUTCHours() !== hour ||
167
+ date.getUTCMinutes() !== minute ||
168
+ date.getUTCSeconds() !== (isLeapSecond ? 59 : second)
169
+ ) {
170
+ return undefined;
171
+ }
172
+
173
+ return { epochMilliseconds: date.getTime(), microsecond };
174
+ }
175
+
176
+ private static requireTimestampField(value: number | undefined, fieldName: string): number {
177
+ if (value === undefined) {
178
+ throw new TypeError(`required property '${fieldName}' missing or undefined`);
179
+ }
180
+
181
+ return value;
182
+ }
183
+
184
+ private static requireWholeNumber(value: number, fieldName: string): number {
185
+ if (!Number.isFinite(value) || !Number.isInteger(value)) {
186
+ throw new RangeError(`${fieldName} must be a finite integer`);
187
+ }
188
+
189
+ return value;
190
+ }
73
191
  }