@enbox/dwn-sdk-js 0.4.6 → 0.4.7

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 (371) 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 +1997 -1517
  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 +28 -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 +7 -10
  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 +32 -274
  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 +116 -472
  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/protocols/protocols-configure.spec.js +152 -0
  199. package/dist/esm/tests/validation/json-schemas/protocols/protocols-configure.spec.js.map +1 -1
  200. package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js +46 -1
  201. package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js.map +1 -1
  202. package/dist/types/generated/precompiled-validators.d.ts +4 -4
  203. package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
  204. package/dist/types/src/core/constants.d.ts +39 -0
  205. package/dist/types/src/core/constants.d.ts.map +1 -1
  206. package/dist/types/src/core/dwn-error.d.ts +28 -11
  207. package/dist/types/src/core/dwn-error.d.ts.map +1 -1
  208. package/dist/types/src/core/encryption-control.d.ts +128 -0
  209. package/dist/types/src/core/encryption-control.d.ts.map +1 -0
  210. package/dist/types/src/core/message.d.ts +4 -0
  211. package/dist/types/src/core/message.d.ts.map +1 -1
  212. package/dist/types/src/core/messages-grant-authorization.d.ts +11 -0
  213. package/dist/types/src/core/messages-grant-authorization.d.ts.map +1 -1
  214. package/dist/types/src/core/protocol-authorization-action.d.ts.map +1 -1
  215. package/dist/types/src/core/protocol-authorization-validation.d.ts.map +1 -1
  216. package/dist/types/src/core/protocol-authorization.d.ts.map +1 -1
  217. package/dist/types/src/core/recording-validation-state-reader.d.ts +2 -3
  218. package/dist/types/src/core/recording-validation-state-reader.d.ts.map +1 -1
  219. package/dist/types/src/core/replication-apply.d.ts +10 -1
  220. package/dist/types/src/core/replication-apply.d.ts.map +1 -1
  221. package/dist/types/src/core/validation-state-reader.d.ts +2 -3
  222. package/dist/types/src/core/validation-state-reader.d.ts.map +1 -1
  223. package/dist/types/src/dwn.d.ts.map +1 -1
  224. package/dist/types/src/event-stream/event-emitter-wake-publisher.d.ts +1 -1
  225. package/dist/types/src/event-stream/event-emitter-wake-publisher.d.ts.map +1 -1
  226. package/dist/types/src/handlers/messages-query.d.ts.map +1 -1
  227. package/dist/types/src/handlers/messages-read.d.ts.map +1 -1
  228. package/dist/types/src/handlers/messages-subscribe.d.ts.map +1 -1
  229. package/dist/types/src/handlers/protocols-configure.d.ts +1 -0
  230. package/dist/types/src/handlers/protocols-configure.d.ts.map +1 -1
  231. package/dist/types/src/handlers/records-count.d.ts +2 -0
  232. package/dist/types/src/handlers/records-count.d.ts.map +1 -1
  233. package/dist/types/src/handlers/records-delete.d.ts.map +1 -1
  234. package/dist/types/src/handlers/records-query.d.ts +3 -0
  235. package/dist/types/src/handlers/records-query.d.ts.map +1 -1
  236. package/dist/types/src/handlers/records-read.d.ts.map +1 -1
  237. package/dist/types/src/handlers/records-subscribe.d.ts +2 -0
  238. package/dist/types/src/handlers/records-subscribe.d.ts.map +1 -1
  239. package/dist/types/src/handlers/records-write.d.ts.map +1 -1
  240. package/dist/types/src/index.d.ts +10 -17
  241. package/dist/types/src/index.d.ts.map +1 -1
  242. package/dist/types/src/interfaces/protocols-configure.d.ts +13 -1
  243. package/dist/types/src/interfaces/protocols-configure.d.ts.map +1 -1
  244. package/dist/types/src/interfaces/records-write.d.ts +5 -1
  245. package/dist/types/src/interfaces/records-write.d.ts.map +1 -1
  246. package/dist/types/src/jose/algorithms/signing/ed25519.d.ts.map +1 -1
  247. package/dist/types/src/protocols/encryption.d.ts +2 -19
  248. package/dist/types/src/protocols/encryption.d.ts.map +1 -1
  249. package/dist/types/src/store/blockstore-level.d.ts +11 -11
  250. package/dist/types/src/store/blockstore-level.d.ts.map +1 -1
  251. package/dist/types/src/store/blockstore-mock.d.ts +12 -12
  252. package/dist/types/src/store/blockstore-mock.d.ts.map +1 -1
  253. package/dist/types/src/store/blockstore-utils.d.ts +23 -0
  254. package/dist/types/src/store/blockstore-utils.d.ts.map +1 -0
  255. package/dist/types/src/store/blockstore.d.ts +3 -0
  256. package/dist/types/src/store/blockstore.d.ts.map +1 -0
  257. package/dist/types/src/store/data-store-level.d.ts.map +1 -1
  258. package/dist/types/src/store/level.d.ts +13 -0
  259. package/dist/types/src/store/level.d.ts.map +1 -0
  260. package/dist/types/src/types/cache.d.ts +2 -2
  261. package/dist/types/src/types/cache.d.ts.map +1 -1
  262. package/dist/types/src/types/encryption-types.d.ts +31 -2
  263. package/dist/types/src/types/encryption-types.d.ts.map +1 -1
  264. package/dist/types/src/types/validation-state-reader.d.ts +3 -5
  265. package/dist/types/src/types/validation-state-reader.d.ts.map +1 -1
  266. package/dist/types/src/utils/data-stream.d.ts +5 -0
  267. package/dist/types/src/utils/data-stream.d.ts.map +1 -1
  268. package/dist/types/src/utils/encryption.d.ts +53 -24
  269. package/dist/types/src/utils/encryption.d.ts.map +1 -1
  270. package/dist/types/src/utils/grant-key-coverage.d.ts +36 -0
  271. package/dist/types/src/utils/grant-key-coverage.d.ts.map +1 -0
  272. package/dist/types/src/utils/hd-key.d.ts.map +1 -1
  273. package/dist/types/src/utils/jws.d.ts.map +1 -1
  274. package/dist/types/src/utils/memory-cache.d.ts +4 -2
  275. package/dist/types/src/utils/memory-cache.d.ts.map +1 -1
  276. package/dist/types/src/utils/protocols.d.ts +11 -0
  277. package/dist/types/src/utils/protocols.d.ts.map +1 -1
  278. package/dist/types/src/utils/record-limit-occupancy.d.ts +7 -0
  279. package/dist/types/src/utils/record-limit-occupancy.d.ts.map +1 -1
  280. package/dist/types/src/utils/records.d.ts +2 -0
  281. package/dist/types/src/utils/records.d.ts.map +1 -1
  282. package/dist/types/src/utils/secp256k1.d.ts.map +1 -1
  283. package/dist/types/src/utils/secp256r1.d.ts.map +1 -1
  284. package/dist/types/src/utils/time.d.ts +21 -13
  285. package/dist/types/src/utils/time.d.ts.map +1 -1
  286. package/dist/types/tests/core/constants.spec.d.ts +2 -0
  287. package/dist/types/tests/core/constants.spec.d.ts.map +1 -0
  288. package/dist/types/tests/core/encryption-control.spec.d.ts +2 -0
  289. package/dist/types/tests/core/encryption-control.spec.d.ts.map +1 -0
  290. package/dist/types/tests/dwn.spec.d.ts.map +1 -1
  291. package/dist/types/tests/event-emitter-wake-publisher.spec.d.ts +2 -0
  292. package/dist/types/tests/event-emitter-wake-publisher.spec.d.ts.map +1 -0
  293. package/dist/types/tests/handlers/messages-query.spec.d.ts.map +1 -1
  294. package/dist/types/tests/handlers/messages-read.spec.d.ts.map +1 -1
  295. package/dist/types/tests/handlers/messages-subscribe.spec.d.ts.map +1 -1
  296. package/dist/types/tests/handlers/protocols-configure.spec.d.ts.map +1 -1
  297. package/dist/types/tests/handlers/records-count.spec.d.ts.map +1 -1
  298. package/dist/types/tests/handlers/records-delete.spec.d.ts.map +1 -1
  299. package/dist/types/tests/handlers/records-query.spec.d.ts.map +1 -1
  300. package/dist/types/tests/handlers/records-read.spec.d.ts.map +1 -1
  301. package/dist/types/tests/handlers/records-subscribe.spec.d.ts.map +1 -1
  302. package/dist/types/tests/handlers/records-write.spec.d.ts.map +1 -1
  303. package/dist/types/tests/scenarios/end-to-end-tests.spec.d.ts.map +1 -1
  304. package/dist/types/tests/store/blockstore-utils.spec.d.ts +2 -0
  305. package/dist/types/tests/store/blockstore-utils.spec.d.ts.map +1 -0
  306. package/dist/types/tests/test-stores.d.ts.map +1 -1
  307. package/dist/types/tests/utils/encryption-control-test-utils.d.ts +46 -0
  308. package/dist/types/tests/utils/encryption-control-test-utils.d.ts.map +1 -0
  309. package/dist/types/tests/utils/grant-key-coverage.spec.d.ts +2 -0
  310. package/dist/types/tests/utils/grant-key-coverage.spec.d.ts.map +1 -0
  311. package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -1
  312. package/dist/types/tests/validation/json-schemas/encryption/audience.spec.d.ts +2 -0
  313. package/dist/types/tests/validation/json-schemas/encryption/audience.spec.d.ts.map +1 -0
  314. package/dist/types/tests/validation/json-schemas/encryption/delivery.spec.d.ts +2 -0
  315. package/dist/types/tests/validation/json-schemas/encryption/delivery.spec.d.ts.map +1 -0
  316. package/package.json +47 -28
  317. package/src/core/constants.ts +61 -0
  318. package/src/core/dwn-error.ts +28 -11
  319. package/src/core/encryption-control.ts +1249 -0
  320. package/src/core/message.ts +7 -0
  321. package/src/core/messages-grant-authorization.ts +60 -9
  322. package/src/core/protocol-authorization-action.ts +3 -13
  323. package/src/core/protocol-authorization-validation.ts +66 -46
  324. package/src/core/protocol-authorization.ts +7 -0
  325. package/src/core/recording-validation-state-reader.ts +4 -5
  326. package/src/core/replication-apply.ts +77 -133
  327. package/src/core/validation-state-reader.ts +6 -8
  328. package/src/dwn.ts +1 -2
  329. package/src/event-stream/event-emitter-wake-publisher.ts +10 -14
  330. package/src/handlers/messages-query.ts +6 -22
  331. package/src/handlers/messages-read.ts +4 -3
  332. package/src/handlers/messages-subscribe.ts +34 -30
  333. package/src/handlers/protocols-configure.ts +7 -4
  334. package/src/handlers/records-count.ts +111 -10
  335. package/src/handlers/records-delete.ts +15 -0
  336. package/src/handlers/records-query.ts +176 -20
  337. package/src/handlers/records-read.ts +19 -6
  338. package/src/handlers/records-subscribe.ts +158 -8
  339. package/src/handlers/records-write.ts +19 -0
  340. package/src/index.ts +48 -21
  341. package/src/interfaces/protocols-configure.ts +102 -11
  342. package/src/interfaces/records-write.ts +49 -43
  343. package/src/jose/algorithms/signing/ed25519.ts +7 -6
  344. package/src/jose/jws/general/verifier.ts +3 -3
  345. package/src/protocols/encryption.ts +50 -420
  346. package/src/store/blockstore-level.ts +33 -37
  347. package/src/store/blockstore-mock.ts +24 -38
  348. package/src/store/blockstore-utils.ts +85 -0
  349. package/src/store/blockstore.ts +8 -0
  350. package/src/store/data-store-level.ts +5 -12
  351. package/src/store/level.ts +19 -0
  352. package/src/types/cache.ts +3 -3
  353. package/src/types/encryption-types.ts +39 -2
  354. package/src/types/validation-state-reader.ts +3 -5
  355. package/src/utils/data-stream.ts +29 -1
  356. package/src/utils/encryption.ts +190 -60
  357. package/src/utils/grant-key-coverage.ts +303 -0
  358. package/src/utils/hd-key.ts +1 -2
  359. package/src/utils/jws.ts +8 -2
  360. package/src/utils/memory-cache.ts +42 -11
  361. package/src/utils/protocols.ts +32 -0
  362. package/src/utils/record-limit-occupancy.ts +34 -5
  363. package/src/utils/records.ts +36 -2
  364. package/src/utils/secp256k1.ts +12 -12
  365. package/src/utils/secp256r1.ts +12 -22
  366. package/src/utils/time.ts +145 -27
  367. package/dist/esm/tests/validation/json-schemas/encryption/audience-key.spec.js +0 -40
  368. package/dist/esm/tests/validation/json-schemas/encryption/audience-key.spec.js.map +0 -1
  369. package/dist/types/tests/validation/json-schemas/encryption/audience-key.spec.d.ts +0 -2
  370. package/dist/types/tests/validation/json-schemas/encryption/audience-key.spec.d.ts.map +0 -1
  371. package/src/types/mitt.d.ts +0 -28
@@ -3,13 +3,14 @@ import type { HandlerDependencies, MethodHandler } from '../types/method-handler
3
3
  import type { RecordsCountMessage, RecordsCountReply } from '../types/records-types.js';
4
4
 
5
5
  import { authenticate } from '../core/auth.js';
6
- import { countRecordsWithRecordLimitOccupancy } from '../utils/record-limit-occupancy.js';
6
+ import { EncryptionControl } from '../core/encryption-control.js';
7
7
  import { Message } from '../core/message.js';
8
8
  import { messageReplyFromError } from '../core/message-reply.js';
9
9
  import { ProtocolAuthorization } from '../core/protocol-authorization.js';
10
10
  import { Records } from '../utils/records.js';
11
11
  import { RecordsCount } from '../interfaces/records-count.js';
12
12
  import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
13
+ import { countRecordsWithRecordLimitOccupancy, queryRecordsWithRecordLimitOccupancy } from '../utils/record-limit-occupancy.js';
13
14
  import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
14
15
 
15
16
  export class RecordsCountHandler implements MethodHandler {
@@ -28,10 +29,11 @@ export class RecordsCountHandler implements MethodHandler {
28
29
  }
29
30
 
30
31
  let count: number;
32
+ const requester = Message.getRequester(recordsCount.message);
31
33
 
32
34
  // if this is an anonymous count and the filter supports published records, count only published records
33
35
  if (Records.filterIncludesPublishedRecords(recordsCount.message.descriptor.filter) && recordsCount.author === undefined) {
34
- count = await this.countPublishedRecords(tenant, recordsCount);
36
+ count = await this.countPublishedRecords(tenant, recordsCount, requester);
35
37
  } else {
36
38
  // authentication and authorization
37
39
  try {
@@ -42,10 +44,12 @@ export class RecordsCountHandler implements MethodHandler {
42
44
  return messageReplyFromError(e, 401);
43
45
  }
44
46
 
45
- if (recordsCount.author === tenant) {
47
+ if (recordsCount.author === tenant && requester === tenant) {
46
48
  count = await this.countRecordsAsOwner(tenant, recordsCount);
49
+ } else if (recordsCount.author === tenant) {
50
+ count = await this.countRecordsAsOwnerDelegate(tenant, recordsCount, requester);
47
51
  } else {
48
- count = await this.countRecordsAsNonOwner(tenant, recordsCount);
52
+ count = await this.countRecordsAsNonOwner(tenant, recordsCount, requester);
49
53
  }
50
54
  }
51
55
 
@@ -70,10 +74,30 @@ export class RecordsCountHandler implements MethodHandler {
70
74
  return this.countProjectedRecords(tenant, recordsCount, [countFilter]);
71
75
  }
72
76
 
77
+ private async countRecordsAsOwnerDelegate(
78
+ tenant: string,
79
+ recordsCount: RecordsCount,
80
+ requester: string | undefined,
81
+ ): Promise<number> {
82
+ const { filter } = recordsCount.message.descriptor;
83
+ const countFilter = {
84
+ ...Records.convertFilter(filter),
85
+ interface : DwnInterfaceName.Records,
86
+ method : DwnMethodName.Write,
87
+ isLatestBaseState : true
88
+ };
89
+
90
+ return this.countProjectedRecordsForRequester(tenant, recordsCount, requester, [countFilter]);
91
+ }
92
+
73
93
  /**
74
94
  * Counts records as a non-owner, applying the same filter logic as RecordsQuery.
75
95
  */
76
- private async countRecordsAsNonOwner(tenant: string, recordsCount: RecordsCount): Promise<number> {
96
+ private async countRecordsAsNonOwner(
97
+ tenant: string,
98
+ recordsCount: RecordsCount,
99
+ requester: string | undefined,
100
+ ): Promise<number> {
77
101
  const { filter } = recordsCount.message.descriptor;
78
102
  const filters: Filter[] = [];
79
103
 
@@ -82,6 +106,10 @@ export class RecordsCountHandler implements MethodHandler {
82
106
  }
83
107
 
84
108
  if (Records.filterIncludesUnpublishedRecords(filter)) {
109
+ if (EncryptionControl.isExactAudienceFilter(filter)) {
110
+ filters.push(Records.buildUnpublishedControlRecordsFilter(filter));
111
+ }
112
+
85
113
  if (Records.shouldBuildUnpublishedAuthorFilter(filter, recordsCount.author!)) {
86
114
  filters.push(RecordsCountHandler.buildUnpublishedRecordsByCountAuthorFilter(recordsCount));
87
115
  }
@@ -99,25 +127,89 @@ export class RecordsCountHandler implements MethodHandler {
99
127
  }
100
128
  }
101
129
 
102
- return this.countProjectedRecords(tenant, recordsCount, filters);
130
+ return this.countProjectedRecordsForRequester(tenant, recordsCount, requester, filters);
103
131
  }
104
132
 
105
133
  /**
106
134
  * Counts only published records.
107
135
  */
108
- private async countPublishedRecords(tenant: string, recordsCount: RecordsCount): Promise<number> {
136
+ private async countPublishedRecords(
137
+ tenant: string,
138
+ recordsCount: RecordsCount,
139
+ requester: string | undefined,
140
+ ): Promise<number> {
109
141
  const filter = RecordsCountHandler.buildPublishedRecordsFilter(recordsCount);
110
- return this.countProjectedRecords(tenant, recordsCount, [filter]);
142
+ return this.countProjectedRecordsForRequester(tenant, recordsCount, requester, [filter]);
111
143
  }
112
144
 
113
145
  private async countProjectedRecords(tenant: string, recordsCount: RecordsCount, filters: Filter[]): Promise<number> {
114
- return countRecordsWithRecordLimitOccupancy({
146
+ const totalCount = await countRecordsWithRecordLimitOccupancy({
115
147
  messageStore : this.deps.messageStore,
116
148
  validationStateReader : this.deps.validationStateReader,
117
149
  tenant,
118
150
  filters,
119
151
  messageTimestamp : recordsCount.message.descriptor.messageTimestamp,
120
152
  });
153
+
154
+ const audienceFilters = EncryptionControl.buildAudienceRecordFilters(filters);
155
+ if (audienceFilters.length === 0) {
156
+ return totalCount;
157
+ }
158
+
159
+ const storedAudienceCount = await this.deps.messageStore.count(tenant, audienceFilters);
160
+ if (storedAudienceCount === 0) {
161
+ return totalCount;
162
+ }
163
+
164
+ const { messages } = await this.deps.messageStore.query(tenant, audienceFilters);
165
+ const projectedAudienceMessages = await EncryptionControl.projectCurrentAudienceRecords({
166
+ messageStore : this.deps.messageStore,
167
+ tenant,
168
+ recordsWriteMessages : messages.filter(Records.isRecordsWrite),
169
+ bypassFilters : audienceFilters,
170
+ });
171
+
172
+ return totalCount - storedAudienceCount + projectedAudienceMessages.length;
173
+ }
174
+
175
+ private async countProjectedRecordsForRequester(
176
+ tenant: string,
177
+ recordsCount: RecordsCount,
178
+ requester: string | undefined,
179
+ filters: Filter[],
180
+ ): Promise<number> {
181
+ const controlFilters = Records.buildControlRecordsFilters(filters);
182
+ if (controlFilters.length === 0) {
183
+ return this.countProjectedRecords(tenant, recordsCount, filters);
184
+ }
185
+
186
+ const totalCount = await this.countProjectedRecords(tenant, recordsCount, filters);
187
+ const controlCount = await this.countProjectedRecords(tenant, recordsCount, controlFilters);
188
+ if (controlCount === 0) {
189
+ return totalCount;
190
+ }
191
+
192
+ const { messages } = await queryRecordsWithRecordLimitOccupancy({
193
+ messageStore : this.deps.messageStore,
194
+ validationStateReader : this.deps.validationStateReader,
195
+ tenant,
196
+ filters : controlFilters,
197
+ messageTimestamp : recordsCount.message.descriptor.messageTimestamp,
198
+ });
199
+ const projectedMessages = await EncryptionControl.projectCurrentAudienceRecords({
200
+ messageStore : this.deps.messageStore,
201
+ tenant,
202
+ recordsWriteMessages : messages,
203
+ bypassFilters : controlFilters,
204
+ });
205
+ const visibleMessages = await EncryptionControl.filterVisibleControlRecords({
206
+ tenant,
207
+ incomingMessage : recordsCount.message,
208
+ requester,
209
+ recordsWriteMessages : projectedMessages,
210
+ validationStateReader : this.deps.validationStateReader,
211
+ });
212
+ return totalCount - controlCount + visibleMessages.length;
121
213
  }
122
214
 
123
215
  private static buildPublishedRecordsFilter(recordsCount: RecordsCount): Filter {
@@ -198,8 +290,16 @@ export class RecordsCountHandler implements MethodHandler {
198
290
  deps: HandlerDependencies,
199
291
  ): Promise<void> {
200
292
 
201
- if (Message.isSignedByAuthorDelegate(recordsCount.message)) {
293
+ if (Message.isSignedByAuthorDelegate(recordsCount.message) &&
294
+ !EncryptionControl.filterTargetsOnlyControlRecords(recordsCount.message.descriptor.filter)) {
202
295
  await recordsCount.authorizeDelegate(deps.validationStateReader);
296
+ } else if (EncryptionControl.filterTargetsOnlyControlRecords(recordsCount.message.descriptor.filter)) {
297
+ await EncryptionControl.authorizeControlReadRequest({
298
+ tenant,
299
+ incomingMessage : recordsCount.message,
300
+ requester : Message.getRequester(recordsCount.message),
301
+ validationStateReader : deps.validationStateReader,
302
+ });
203
303
  }
204
304
 
205
305
  const permissionGrantId = Message.getPermissionGrantId(recordsCount.signaturePayload!);
@@ -222,4 +322,5 @@ export class RecordsCountHandler implements MethodHandler {
222
322
  await ProtocolAuthorization.authorizeQueryOrSubscribe(tenant, recordsCount, deps.validationStateReader);
223
323
  }
224
324
  }
325
+
225
326
  }
@@ -6,6 +6,7 @@ import type { HandlerDependencies, MethodHandler } from '../types/method-handler
6
6
 
7
7
  import { authenticate } from '../core/auth.js';
8
8
  import { DwnInterfaceName } from '../enums/dwn-interface-method.js';
9
+ import { EncryptionControl } from '../core/encryption-control.js';
9
10
  import { Message } from '../core/message.js';
10
11
  import { messageReplyFromError } from '../core/message-reply.js';
11
12
  import { ProtocolAuthorization } from '../core/protocol-authorization.js';
@@ -13,6 +14,7 @@ import { Records } from '../utils/records.js';
13
14
  import { RecordsDelete } from '../interfaces/records-delete.js';
14
15
  import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
15
16
  import { ResumableTaskName } from '../core/resumable-task-manager.js';
17
+ import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
16
18
 
17
19
  export class RecordsDeleteHandler implements MethodHandler {
18
20
 
@@ -71,6 +73,12 @@ export class RecordsDeleteHandler implements MethodHandler {
71
73
  // but if the latest record state is a RecordsDelete (ie. when we are pruning a non-prune delete),
72
74
  // we'd need to use the initial write because RecordsDelete does not contain the immutable properties needed for processing.
73
75
  const initialWrite = await this.deps.validationStateReader.fetchInitialRecordsWrite(tenant, message.descriptor.recordId);
76
+ if (EncryptionControl.isControlMessage(initialWrite!.message)) {
77
+ throw new DwnError(
78
+ DwnErrorCode.EncryptionControlValidateUnexpectedRecord,
79
+ 'encryption control records cannot be deleted.'
80
+ );
81
+ }
74
82
 
75
83
  await this.authorizeRecordsDelete(
76
84
  tenant,
@@ -79,6 +87,13 @@ export class RecordsDeleteHandler implements MethodHandler {
79
87
  );
80
88
 
81
89
  } catch (e) {
90
+ if (e instanceof DwnError) {
91
+ const statusCode = EncryptionControl.mapErrorToStatusCode(e.code);
92
+ if (statusCode !== undefined) {
93
+ return messageReplyFromError(e, statusCode);
94
+ }
95
+ }
96
+
82
97
  return messageReplyFromError(e, 401);
83
98
  }
84
99
 
@@ -5,6 +5,7 @@ import type { RecordsQueryMessage, RecordsQueryReply, RecordsQueryReplyEntry } f
5
5
 
6
6
  import { authenticate } from '../core/auth.js';
7
7
  import { DateSort } from '../types/records-types.js';
8
+ import { EncryptionControl } from '../core/encryption-control.js';
8
9
  import { Message } from '../core/message.js';
9
10
  import { messageReplyFromError } from '../core/message-reply.js';
10
11
  import { ProtocolAuthorization } from '../core/protocol-authorization.js';
@@ -33,9 +34,10 @@ export class RecordsQueryHandler implements MethodHandler {
33
34
 
34
35
  let recordsWrites: RecordsQueryReplyEntry[];
35
36
  let cursor: PaginationCursor | undefined;
37
+ const requester = Message.getRequester(recordsQuery.message);
36
38
  // if this is an anonymous query and the filter supports published records, query only published records
37
39
  if (Records.filterIncludesPublishedRecords(recordsQuery.message.descriptor.filter) && recordsQuery.author === undefined) {
38
- const results = await this.fetchPublishedRecords(tenant, recordsQuery);
40
+ const results = await this.fetchPublishedRecords(tenant, recordsQuery, requester);
39
41
  recordsWrites = results.messages as RecordsQueryReplyEntry[];
40
42
  cursor = results.cursor;
41
43
  } else {
@@ -49,11 +51,13 @@ export class RecordsQueryHandler implements MethodHandler {
49
51
  }
50
52
 
51
53
  if (recordsQuery.author === tenant) {
52
- const results = await this.fetchRecordsAsOwner(tenant, recordsQuery);
54
+ const results = requester === tenant
55
+ ? await this.fetchRecordsAsOwner(tenant, recordsQuery)
56
+ : await this.fetchRecordsAsOwnerDelegate(tenant, recordsQuery, requester);
53
57
  recordsWrites = results.messages as RecordsQueryReplyEntry[];
54
58
  cursor = results.cursor;
55
59
  } else {
56
- const results = await this.fetchRecordsAsNonOwner(tenant, recordsQuery);
60
+ const results = await this.fetchRecordsAsNonOwner(tenant, recordsQuery, requester);
57
61
  recordsWrites = results.messages as RecordsQueryReplyEntry[];
58
62
  cursor = results.cursor;
59
63
  }
@@ -122,14 +126,37 @@ export class RecordsQueryHandler implements MethodHandler {
122
126
  };
123
127
 
124
128
  const messageSort = this.convertDateSort(dateSort);
125
- return queryRecordsWithRecordLimitOccupancy({
126
- messageStore : this.deps.messageStore,
127
- validationStateReader : this.deps.validationStateReader,
129
+ return this.queryRecordsWithVisibleControlFiltering({
128
130
  tenant,
129
- filters : [queryFilter],
131
+ recordsQuery,
132
+ requester : tenant,
133
+ filters : [queryFilter],
134
+ messageSort,
135
+ pagination,
136
+ });
137
+ }
138
+
139
+ private async fetchRecordsAsOwnerDelegate(
140
+ tenant: string,
141
+ recordsQuery: RecordsQuery,
142
+ requester: string | undefined,
143
+ ): Promise<{ messages: GenericMessage[], cursor?: PaginationCursor }> {
144
+ const { dateSort, filter, pagination } = recordsQuery.message.descriptor;
145
+ const queryFilter = {
146
+ ...Records.convertFilter(filter, dateSort),
147
+ interface : DwnInterfaceName.Records,
148
+ method : DwnMethodName.Write,
149
+ isLatestBaseState : true
150
+ };
151
+
152
+ const messageSort = this.convertDateSort(dateSort);
153
+ return this.queryRecordsWithVisibleControlFiltering({
154
+ tenant,
155
+ recordsQuery,
156
+ requester,
157
+ filters: [queryFilter],
130
158
  messageSort,
131
159
  pagination,
132
- messageTimestamp : recordsQuery.message.descriptor.messageTimestamp,
133
160
  });
134
161
  }
135
162
 
@@ -153,7 +180,9 @@ export class RecordsQueryHandler implements MethodHandler {
153
180
  *
154
181
  */
155
182
  private async fetchRecordsAsNonOwner(
156
- tenant: string, recordsQuery: RecordsQuery
183
+ tenant: string,
184
+ recordsQuery: RecordsQuery,
185
+ requester: string | undefined,
157
186
  ): Promise<{ messages: GenericMessage[], cursor?: PaginationCursor }> {
158
187
  const { dateSort, pagination, filter } = recordsQuery.message.descriptor;
159
188
  const filters = [];
@@ -162,6 +191,10 @@ export class RecordsQueryHandler implements MethodHandler {
162
191
  }
163
192
 
164
193
  if (Records.filterIncludesUnpublishedRecords(filter)) {
194
+ if (EncryptionControl.isExactAudienceFilter(filter)) {
195
+ filters.push(Records.buildUnpublishedControlRecordsFilter(filter, dateSort));
196
+ }
197
+
165
198
  if (Records.shouldBuildUnpublishedAuthorFilter(filter, recordsQuery.author!)) {
166
199
  filters.push(RecordsQueryHandler.buildUnpublishedRecordsByQueryAuthorFilter(recordsQuery));
167
200
  }
@@ -180,14 +213,13 @@ export class RecordsQueryHandler implements MethodHandler {
180
213
  }
181
214
 
182
215
  const messageSort = this.convertDateSort(dateSort);
183
- return queryRecordsWithRecordLimitOccupancy({
184
- messageStore : this.deps.messageStore,
185
- validationStateReader : this.deps.validationStateReader,
216
+ return this.queryRecordsWithVisibleControlFiltering({
186
217
  tenant,
218
+ recordsQuery,
219
+ requester,
187
220
  filters,
188
221
  messageSort,
189
222
  pagination,
190
- messageTimestamp : recordsQuery.message.descriptor.messageTimestamp,
191
223
  });
192
224
  }
193
225
 
@@ -195,22 +227,123 @@ export class RecordsQueryHandler implements MethodHandler {
195
227
  * Fetches only published records.
196
228
  */
197
229
  private async fetchPublishedRecords(
198
- tenant: string, recordsQuery: RecordsQuery
230
+ tenant: string,
231
+ recordsQuery: RecordsQuery,
232
+ requester: string | undefined,
199
233
  ): Promise<{ messages: GenericMessage[], cursor?: PaginationCursor }> {
200
234
  const { dateSort, pagination } = recordsQuery.message.descriptor;
201
235
  const filter = RecordsQueryHandler.buildPublishedRecordsFilter(recordsQuery);
202
236
  const messageSort = this.convertDateSort(dateSort);
203
- return queryRecordsWithRecordLimitOccupancy({
204
- messageStore : this.deps.messageStore,
205
- validationStateReader : this.deps.validationStateReader,
237
+ return this.queryRecordsWithVisibleControlFiltering({
206
238
  tenant,
207
- filters : [filter],
239
+ recordsQuery,
240
+ requester,
241
+ filters: [filter],
208
242
  messageSort,
209
243
  pagination,
210
- messageTimestamp : recordsQuery.message.descriptor.messageTimestamp,
211
244
  });
212
245
  }
213
246
 
247
+ private async queryRecordsWithVisibleControlFiltering(input: {
248
+ tenant: string;
249
+ recordsQuery: RecordsQuery;
250
+ requester: string | undefined;
251
+ filters: Filter[];
252
+ messageSort: MessageSort;
253
+ pagination?: { cursor?: PaginationCursor; limit?: number };
254
+ }): Promise<{ messages: RecordsQueryReplyEntry[], cursor?: PaginationCursor }> {
255
+ const {
256
+ tenant, recordsQuery, requester, filters, messageSort, pagination
257
+ } = input;
258
+ const controlFilters = Records.buildControlRecordsFilters(filters);
259
+ const currentAudienceRecordIdCache = new Map<string, string | undefined>();
260
+ if (controlFilters.length === 0) {
261
+ const result = await queryRecordsWithRecordLimitOccupancy({
262
+ messageStore : this.deps.messageStore,
263
+ validationStateReader : this.deps.validationStateReader,
264
+ tenant,
265
+ filters,
266
+ messageSort,
267
+ pagination,
268
+ messageTimestamp : recordsQuery.message.descriptor.messageTimestamp,
269
+ });
270
+ return EncryptionControl.projectCurrentAudienceRecordPage({
271
+ messageStore : this.deps.messageStore,
272
+ tenant,
273
+ filters,
274
+ currentAudienceRecordIdCache,
275
+ result : {
276
+ messages : result.messages as RecordsQueryReplyEntry[],
277
+ cursor : result.cursor,
278
+ },
279
+ });
280
+ }
281
+
282
+ if (pagination?.limit === undefined || pagination.limit <= 0) {
283
+ const result = await queryRecordsWithRecordLimitOccupancy({
284
+ messageStore : this.deps.messageStore,
285
+ validationStateReader : this.deps.validationStateReader,
286
+ tenant,
287
+ filters,
288
+ messageSort,
289
+ pagination,
290
+ messageTimestamp : recordsQuery.message.descriptor.messageTimestamp,
291
+ });
292
+ const projectedResult = await EncryptionControl.projectCurrentAudienceRecordPage({
293
+ messageStore : this.deps.messageStore,
294
+ tenant,
295
+ filters,
296
+ currentAudienceRecordIdCache,
297
+ result : {
298
+ messages : result.messages as RecordsQueryReplyEntry[],
299
+ cursor : result.cursor,
300
+ },
301
+ });
302
+ return {
303
+ messages : await this.filterControlRecordsForRequester(tenant, recordsQuery, requester, projectedResult.messages),
304
+ cursor : projectedResult.cursor,
305
+ };
306
+ }
307
+
308
+ const visibleMessages: RecordsQueryReplyEntry[] = [];
309
+ let cursor = pagination.cursor;
310
+ let nextCursor: PaginationCursor | undefined;
311
+ // Keeps visible-page pagination stable until #1100 moves control visibility into indexed store filters.
312
+ do {
313
+ const remainingLimit = pagination.limit - visibleMessages.length;
314
+ const result = await queryRecordsWithRecordLimitOccupancy({
315
+ messageStore : this.deps.messageStore,
316
+ validationStateReader : this.deps.validationStateReader,
317
+ tenant,
318
+ filters,
319
+ messageSort,
320
+ pagination : { ...pagination, cursor, limit: remainingLimit },
321
+ messageTimestamp : recordsQuery.message.descriptor.messageTimestamp,
322
+ });
323
+ const projectedResult = await EncryptionControl.projectCurrentAudienceRecordPage({
324
+ messageStore : this.deps.messageStore,
325
+ tenant,
326
+ filters,
327
+ currentAudienceRecordIdCache,
328
+ result : {
329
+ messages : result.messages as RecordsQueryReplyEntry[],
330
+ cursor : result.cursor,
331
+ },
332
+ });
333
+ const filteredMessages = await this.filterControlRecordsForRequester(
334
+ tenant,
335
+ recordsQuery,
336
+ requester,
337
+ projectedResult.messages,
338
+ );
339
+ visibleMessages.push(...filteredMessages);
340
+ nextCursor = projectedResult.cursor;
341
+ cursor = projectedResult.cursor;
342
+ } while (visibleMessages.length < pagination.limit && cursor !== undefined);
343
+
344
+ return { messages: visibleMessages, cursor: nextCursor };
345
+ }
346
+
214
347
  private static buildPublishedRecordsFilter(recordsQuery: RecordsQuery): Filter {
215
348
  const { dateSort, filter } = recordsQuery.message.descriptor;
216
349
  // fetch all published records matching the query
@@ -293,8 +426,16 @@ export class RecordsQueryHandler implements MethodHandler {
293
426
  deps: HandlerDependencies,
294
427
  ): Promise<void> {
295
428
 
296
- if (Message.isSignedByAuthorDelegate(recordsQuery.message)) {
429
+ if (Message.isSignedByAuthorDelegate(recordsQuery.message) &&
430
+ !EncryptionControl.filterTargetsOnlyControlRecords(recordsQuery.message.descriptor.filter)) {
297
431
  await recordsQuery.authorizeDelegate(deps.validationStateReader);
432
+ } else if (EncryptionControl.filterTargetsOnlyControlRecords(recordsQuery.message.descriptor.filter)) {
433
+ await EncryptionControl.authorizeControlReadRequest({
434
+ tenant,
435
+ incomingMessage : recordsQuery.message,
436
+ requester : Message.getRequester(recordsQuery.message),
437
+ validationStateReader : deps.validationStateReader,
438
+ });
298
439
  }
299
440
 
300
441
  const permissionGrantId = Message.getPermissionGrantId(recordsQuery.signaturePayload!);
@@ -317,4 +458,19 @@ export class RecordsQueryHandler implements MethodHandler {
317
458
  await ProtocolAuthorization.authorizeQueryOrSubscribe(tenant, recordsQuery, deps.validationStateReader);
318
459
  }
319
460
  }
461
+
462
+ private async filterControlRecordsForRequester(
463
+ tenant: string,
464
+ recordsQuery: RecordsQuery,
465
+ requester: string | undefined,
466
+ recordsWrites: RecordsQueryReplyEntry[],
467
+ ): Promise<RecordsQueryReplyEntry[]> {
468
+ return EncryptionControl.filterVisibleControlRecords({
469
+ tenant,
470
+ incomingMessage : recordsQuery.message,
471
+ requester,
472
+ recordsWriteMessages : recordsWrites,
473
+ validationStateReader : this.deps.validationStateReader,
474
+ });
475
+ }
320
476
  }
@@ -5,6 +5,7 @@ import type { RecordsDeleteMessage, RecordsQueryReplyEntry, RecordsReadMessage,
5
5
  import { authenticate } from '../core/auth.js';
6
6
  import { DataStream } from '../utils/data-stream.js';
7
7
  import { Encoder } from '../utils/encoder.js';
8
+ import { EncryptionControl } from '../core/encryption-control.js';
8
9
  import { isRecordLimitOccupant } from '../utils/record-limit-occupancy.js';
9
10
  import { Message } from '../core/message.js';
10
11
  import { messageReplyFromError } from '../core/message-reply.js';
@@ -178,14 +179,26 @@ export class RecordsReadHandler implements MethodHandler {
178
179
  matchedRecordsWrite: RecordsWrite,
179
180
  deps: HandlerDependencies,
180
181
  ): Promise<void> {
181
- if (Message.isSignedByAuthorDelegate(recordsRead.message)) {
182
- await recordsRead.authorizeDelegate(matchedRecordsWrite.message, deps.validationStateReader);
183
- }
184
-
185
182
  const { descriptor } = matchedRecordsWrite.message;
186
183
 
187
- // if author is the same as the target tenant, we can directly grant access
188
- if (recordsRead.author === tenant) {
184
+ if (EncryptionControl.isControlMessage(matchedRecordsWrite.message)) {
185
+ await EncryptionControl.authorizeControlReadRequest({
186
+ tenant,
187
+ incomingMessage : recordsRead.message,
188
+ requester : Message.getRequester(recordsRead.message),
189
+ validationStateReader : deps.validationStateReader,
190
+ });
191
+ await EncryptionControl.authorizeRead({
192
+ tenant,
193
+ incomingMessage : recordsRead.message,
194
+ requester : Message.getRequester(recordsRead.message),
195
+ recordsWriteMessage : matchedRecordsWrite.message,
196
+ validationStateReader : deps.validationStateReader,
197
+ });
198
+ } else if (Message.isSignedByAuthorDelegate(recordsRead.message)) {
199
+ await recordsRead.authorizeDelegate(matchedRecordsWrite.message, deps.validationStateReader);
200
+ } else if (recordsRead.author === tenant) {
201
+ // if author is the same as the target tenant, we can directly grant access
189
202
  return;
190
203
  } else if (descriptor.published === true) {
191
204
  // authentication is not required for published data