@enbox/dwn-sdk-js 0.4.0 → 0.4.1

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 (513) hide show
  1. package/README.md +4 -4
  2. package/dist/browser.mjs +8 -8
  3. package/dist/browser.mjs.map +4 -4
  4. package/dist/esm/generated/precompiled-validators.js +799 -885
  5. package/dist/esm/generated/precompiled-validators.js.map +1 -1
  6. package/dist/esm/src/core/dwn-constant.js +5 -0
  7. package/dist/esm/src/core/dwn-constant.js.map +1 -1
  8. package/dist/esm/src/core/dwn-error.js +12 -4
  9. package/dist/esm/src/core/dwn-error.js.map +1 -1
  10. package/dist/esm/src/core/grant-authorization.js +9 -18
  11. package/dist/esm/src/core/grant-authorization.js.map +1 -1
  12. package/dist/esm/src/core/message-reply.js.map +1 -1
  13. package/dist/esm/src/core/messages-grant-authorization.js +28 -45
  14. package/dist/esm/src/core/messages-grant-authorization.js.map +1 -1
  15. package/dist/esm/src/core/protocol-authorization-action.js +25 -27
  16. package/dist/esm/src/core/protocol-authorization-action.js.map +1 -1
  17. package/dist/esm/src/core/protocol-authorization-validation.js +30 -68
  18. package/dist/esm/src/core/protocol-authorization-validation.js.map +1 -1
  19. package/dist/esm/src/core/protocol-authorization.js +44 -118
  20. package/dist/esm/src/core/protocol-authorization.js.map +1 -1
  21. package/dist/esm/src/core/protocols-grant-authorization.js +5 -5
  22. package/dist/esm/src/core/protocols-grant-authorization.js.map +1 -1
  23. package/dist/esm/src/core/recording-validation-state-reader.js +84 -0
  24. package/dist/esm/src/core/recording-validation-state-reader.js.map +1 -0
  25. package/dist/esm/src/core/records-grant-authorization.js +11 -11
  26. package/dist/esm/src/core/records-grant-authorization.js.map +1 -1
  27. package/dist/esm/src/core/replication-apply.js +123 -28
  28. package/dist/esm/src/core/replication-apply.js.map +1 -1
  29. package/dist/esm/src/core/resumable-task-manager.js +5 -4
  30. package/dist/esm/src/core/resumable-task-manager.js.map +1 -1
  31. package/dist/esm/src/core/validation-state-reader.js +237 -0
  32. package/dist/esm/src/core/validation-state-reader.js.map +1 -0
  33. package/dist/esm/src/dwn.js +165 -132
  34. package/dist/esm/src/dwn.js.map +1 -1
  35. package/dist/esm/src/enums/dwn-interface-method.js +0 -1
  36. package/dist/esm/src/enums/dwn-interface-method.js.map +1 -1
  37. package/dist/esm/src/event-stream/durable-event-log.js +365 -0
  38. package/dist/esm/src/event-stream/durable-event-log.js.map +1 -0
  39. package/dist/esm/src/event-stream/event-emitter-wake-publisher.js +25 -0
  40. package/dist/esm/src/event-stream/event-emitter-wake-publisher.js.map +1 -0
  41. package/dist/esm/src/handlers/messages-query.js +159 -0
  42. package/dist/esm/src/handlers/messages-query.js.map +1 -0
  43. package/dist/esm/src/handlers/messages-read.js +5 -5
  44. package/dist/esm/src/handlers/messages-read.js.map +1 -1
  45. package/dist/esm/src/handlers/messages-subscribe.js +8 -8
  46. package/dist/esm/src/handlers/messages-subscribe.js.map +1 -1
  47. package/dist/esm/src/handlers/protocols-configure.js +30 -49
  48. package/dist/esm/src/handlers/protocols-configure.js.map +1 -1
  49. package/dist/esm/src/handlers/protocols-query.js +1 -1
  50. package/dist/esm/src/handlers/protocols-query.js.map +1 -1
  51. package/dist/esm/src/handlers/records-count.js +20 -11
  52. package/dist/esm/src/handlers/records-count.js.map +1 -1
  53. package/dist/esm/src/handlers/records-delete.js +20 -16
  54. package/dist/esm/src/handlers/records-delete.js.map +1 -1
  55. package/dist/esm/src/handlers/records-query.js +35 -11
  56. package/dist/esm/src/handlers/records-query.js.map +1 -1
  57. package/dist/esm/src/handlers/records-read.js +52 -42
  58. package/dist/esm/src/handlers/records-read.js.map +1 -1
  59. package/dist/esm/src/handlers/records-subscribe.js +107 -11
  60. package/dist/esm/src/handlers/records-subscribe.js.map +1 -1
  61. package/dist/esm/src/handlers/records-write.js +62 -116
  62. package/dist/esm/src/handlers/records-write.js.map +1 -1
  63. package/dist/esm/src/index.js +6 -7
  64. package/dist/esm/src/index.js.map +1 -1
  65. package/dist/esm/src/interfaces/{messages-sync.js → messages-query.js} +21 -15
  66. package/dist/esm/src/interfaces/messages-query.js.map +1 -0
  67. package/dist/esm/src/interfaces/protocols-configure.js +7 -3
  68. package/dist/esm/src/interfaces/protocols-configure.js.map +1 -1
  69. package/dist/esm/src/interfaces/protocols-query.js +3 -4
  70. package/dist/esm/src/interfaces/protocols-query.js.map +1 -1
  71. package/dist/esm/src/interfaces/records-count.js +4 -3
  72. package/dist/esm/src/interfaces/records-count.js.map +1 -1
  73. package/dist/esm/src/interfaces/records-delete.js +21 -4
  74. package/dist/esm/src/interfaces/records-delete.js.map +1 -1
  75. package/dist/esm/src/interfaces/records-query.js +4 -3
  76. package/dist/esm/src/interfaces/records-query.js.map +1 -1
  77. package/dist/esm/src/interfaces/records-read.js +3 -3
  78. package/dist/esm/src/interfaces/records-read.js.map +1 -1
  79. package/dist/esm/src/interfaces/records-subscribe.js +4 -3
  80. package/dist/esm/src/interfaces/records-subscribe.js.map +1 -1
  81. package/dist/esm/src/interfaces/records-write.js +27 -13
  82. package/dist/esm/src/interfaces/records-write.js.map +1 -1
  83. package/dist/esm/src/protocols/permissions.js +27 -34
  84. package/dist/esm/src/protocols/permissions.js.map +1 -1
  85. package/dist/esm/src/store/index-level.js +24 -9
  86. package/dist/esm/src/store/index-level.js.map +1 -1
  87. package/dist/esm/src/store/level-wrapper.js +7 -0
  88. package/dist/esm/src/store/level-wrapper.js.map +1 -1
  89. package/dist/esm/src/store/message-store-level.js +536 -42
  90. package/dist/esm/src/store/message-store-level.js.map +1 -1
  91. package/dist/esm/src/store/storage-controller.js +58 -49
  92. package/dist/esm/src/store/storage-controller.js.map +1 -1
  93. package/dist/esm/src/types/message-types.js.map +1 -1
  94. package/dist/esm/src/types/validation-state-reader.js +2 -0
  95. package/dist/esm/src/types/validation-state-reader.js.map +1 -0
  96. package/dist/esm/src/utils/messages.js +17 -0
  97. package/dist/esm/src/utils/messages.js.map +1 -1
  98. package/dist/esm/src/utils/record-limit-occupancy.js +244 -0
  99. package/dist/esm/src/utils/record-limit-occupancy.js.map +1 -0
  100. package/dist/esm/src/utils/records.js +50 -14
  101. package/dist/esm/src/utils/records.js.map +1 -1
  102. package/dist/esm/src/utils/replication.js +85 -0
  103. package/dist/esm/src/utils/replication.js.map +1 -0
  104. package/dist/esm/tests/core/grant-authorization.spec.js +4 -4
  105. package/dist/esm/tests/core/grant-authorization.spec.js.map +1 -1
  106. package/dist/esm/tests/core/process-message-parity.spec.js +222 -0
  107. package/dist/esm/tests/core/process-message-parity.spec.js.map +1 -0
  108. package/dist/esm/tests/core/protocol-authorization.spec.js +5 -2
  109. package/dist/esm/tests/core/protocol-authorization.spec.js.map +1 -1
  110. package/dist/esm/tests/core/records-grant-authorization.spec.js +5 -5
  111. package/dist/esm/tests/core/records-grant-authorization.spec.js.map +1 -1
  112. package/dist/esm/tests/core/replication-apply.spec.js +55 -1
  113. package/dist/esm/tests/core/replication-apply.spec.js.map +1 -1
  114. package/dist/esm/tests/core/replication-replay-property.spec.js +350 -0
  115. package/dist/esm/tests/core/replication-replay-property.spec.js.map +1 -0
  116. package/dist/esm/tests/core/validation-read-closure.spec.js +469 -0
  117. package/dist/esm/tests/core/validation-read-closure.spec.js.map +1 -0
  118. package/dist/esm/tests/core/validation-state-reader.spec.js +716 -0
  119. package/dist/esm/tests/core/validation-state-reader.spec.js.map +1 -0
  120. package/dist/esm/tests/durable-event-log.spec.js +373 -0
  121. package/dist/esm/tests/durable-event-log.spec.js.map +1 -0
  122. package/dist/esm/tests/dwn.spec.js +504 -35
  123. package/dist/esm/tests/dwn.spec.js.map +1 -1
  124. package/dist/esm/tests/features/author-delegated-grant.spec.js +9 -6
  125. package/dist/esm/tests/features/author-delegated-grant.spec.js.map +1 -1
  126. package/dist/esm/tests/features/owner-delegated-grant.spec.js +1 -4
  127. package/dist/esm/tests/features/owner-delegated-grant.spec.js.map +1 -1
  128. package/dist/esm/tests/features/owner-signature.spec.js +1 -4
  129. package/dist/esm/tests/features/owner-signature.spec.js.map +1 -1
  130. package/dist/esm/tests/features/permissions.spec.js +165 -4
  131. package/dist/esm/tests/features/permissions.spec.js.map +1 -1
  132. package/dist/esm/tests/features/protocol-composition.spec.js +8 -11
  133. package/dist/esm/tests/features/protocol-composition.spec.js.map +1 -1
  134. package/dist/esm/tests/features/protocol-create-action.spec.js +1 -4
  135. package/dist/esm/tests/features/protocol-create-action.spec.js.map +1 -1
  136. package/dist/esm/tests/features/protocol-delete-action.spec.js +3 -5
  137. package/dist/esm/tests/features/protocol-delete-action.spec.js.map +1 -1
  138. package/dist/esm/tests/features/protocol-update-action.spec.js +3 -6
  139. package/dist/esm/tests/features/protocol-update-action.spec.js.map +1 -1
  140. package/dist/esm/tests/features/records-delivery.spec.js +1 -4
  141. package/dist/esm/tests/features/records-delivery.spec.js.map +1 -1
  142. package/dist/esm/tests/features/records-immutable.spec.js +1 -4
  143. package/dist/esm/tests/features/records-immutable.spec.js.map +1 -1
  144. package/dist/esm/tests/features/records-nested-query-scope.spec.js +281 -0
  145. package/dist/esm/tests/features/records-nested-query-scope.spec.js.map +1 -0
  146. package/dist/esm/tests/features/records-prune-cross-protocol.spec.js +3 -7
  147. package/dist/esm/tests/features/records-prune-cross-protocol.spec.js.map +1 -1
  148. package/dist/esm/tests/features/records-prune.spec.js +11 -22
  149. package/dist/esm/tests/features/records-prune.spec.js.map +1 -1
  150. package/dist/esm/tests/features/records-record-limit.spec.js +441 -231
  151. package/dist/esm/tests/features/records-record-limit.spec.js.map +1 -1
  152. package/dist/esm/tests/features/records-squash.spec.js +6 -4
  153. package/dist/esm/tests/features/records-squash.spec.js.map +1 -1
  154. package/dist/esm/tests/features/records-tags.spec.js +1 -4
  155. package/dist/esm/tests/features/records-tags.spec.js.map +1 -1
  156. package/dist/esm/tests/features/resumable-tasks.spec.js +3 -5
  157. package/dist/esm/tests/features/resumable-tasks.spec.js.map +1 -1
  158. package/dist/esm/tests/fuzz/message-store.fuzz.spec.js +1 -2
  159. package/dist/esm/tests/fuzz/message-store.fuzz.spec.js.map +1 -1
  160. package/dist/esm/tests/fuzz/process-message.fuzz.spec.js +2 -4
  161. package/dist/esm/tests/fuzz/process-message.fuzz.spec.js.map +1 -1
  162. package/dist/esm/tests/fuzz/schema-validation.fuzz.spec.js +1 -1
  163. package/dist/esm/tests/fuzz/schema-validation.fuzz.spec.js.map +1 -1
  164. package/dist/esm/tests/handlers/messages-query.spec.js +246 -0
  165. package/dist/esm/tests/handlers/messages-query.spec.js.map +1 -0
  166. package/dist/esm/tests/handlers/messages-read.spec.js +2 -5
  167. package/dist/esm/tests/handlers/messages-read.spec.js.map +1 -1
  168. package/dist/esm/tests/handlers/messages-subscribe.spec.js +3 -14
  169. package/dist/esm/tests/handlers/messages-subscribe.spec.js.map +1 -1
  170. package/dist/esm/tests/handlers/protocols-configure.spec.js +27 -26
  171. package/dist/esm/tests/handlers/protocols-configure.spec.js.map +1 -1
  172. package/dist/esm/tests/handlers/protocols-query.spec.js +1 -4
  173. package/dist/esm/tests/handlers/protocols-query.spec.js.map +1 -1
  174. package/dist/esm/tests/handlers/records-count.spec.js +1 -4
  175. package/dist/esm/tests/handlers/records-count.spec.js.map +1 -1
  176. package/dist/esm/tests/handlers/records-delete.spec.js +312 -30
  177. package/dist/esm/tests/handlers/records-delete.spec.js.map +1 -1
  178. package/dist/esm/tests/handlers/records-query.spec.js +32 -9
  179. package/dist/esm/tests/handlers/records-query.spec.js.map +1 -1
  180. package/dist/esm/tests/handlers/records-read.spec.js +4 -4
  181. package/dist/esm/tests/handlers/records-read.spec.js.map +1 -1
  182. package/dist/esm/tests/handlers/records-subscribe.spec.js +33 -14
  183. package/dist/esm/tests/handlers/records-subscribe.spec.js.map +1 -1
  184. package/dist/esm/tests/handlers/records-write.spec.js +82 -36
  185. package/dist/esm/tests/handlers/records-write.spec.js.map +1 -1
  186. package/dist/esm/tests/interfaces/records-delete.spec.js +69 -2
  187. package/dist/esm/tests/interfaces/records-delete.spec.js.map +1 -1
  188. package/dist/esm/tests/interfaces/records-write.spec.js +4 -3
  189. package/dist/esm/tests/interfaces/records-write.spec.js.map +1 -1
  190. package/dist/esm/tests/protocols/permissions.spec.js +55 -6
  191. package/dist/esm/tests/protocols/permissions.spec.js.map +1 -1
  192. package/dist/esm/tests/scenarios/aggregator.spec.js +1 -4
  193. package/dist/esm/tests/scenarios/aggregator.spec.js.map +1 -1
  194. package/dist/esm/tests/scenarios/deleted-record.spec.js +1 -4
  195. package/dist/esm/tests/scenarios/deleted-record.spec.js.map +1 -1
  196. package/dist/esm/tests/scenarios/end-to-end-tests.spec.js +1 -4
  197. package/dist/esm/tests/scenarios/end-to-end-tests.spec.js.map +1 -1
  198. package/dist/esm/tests/scenarios/nested-roles.spec.js +1 -4
  199. package/dist/esm/tests/scenarios/nested-roles.spec.js.map +1 -1
  200. package/dist/esm/tests/scenarios/subscriptions.spec.js +1 -4
  201. package/dist/esm/tests/scenarios/subscriptions.spec.js.map +1 -1
  202. package/dist/esm/tests/store/message-store-level.spec.js +361 -5
  203. package/dist/esm/tests/store/message-store-level.spec.js.map +1 -1
  204. package/dist/esm/tests/store/message-store.spec.js +60 -0
  205. package/dist/esm/tests/store/message-store.spec.js.map +1 -1
  206. package/dist/esm/tests/test-event-stream.js +7 -3
  207. package/dist/esm/tests/test-event-stream.js.map +1 -1
  208. package/dist/esm/tests/test-stores.js +19 -9
  209. package/dist/esm/tests/test-stores.js.map +1 -1
  210. package/dist/esm/tests/test-suite.js +4 -2
  211. package/dist/esm/tests/test-suite.js.map +1 -1
  212. package/dist/esm/tests/utils/test-data-generator.js +25 -0
  213. package/dist/esm/tests/utils/test-data-generator.js.map +1 -1
  214. package/dist/esm/tests/utils/test-stub-generator.js.map +1 -1
  215. package/dist/esm/tests/utils/test-validation-state-reader.js +16 -0
  216. package/dist/esm/tests/utils/test-validation-state-reader.js.map +1 -0
  217. package/dist/types/generated/precompiled-validators.d.ts +6 -6
  218. package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
  219. package/dist/types/src/core/core-protocol.d.ts +3 -3
  220. package/dist/types/src/core/core-protocol.d.ts.map +1 -1
  221. package/dist/types/src/core/dwn-constant.d.ts +5 -0
  222. package/dist/types/src/core/dwn-constant.d.ts.map +1 -1
  223. package/dist/types/src/core/dwn-error.d.ts +12 -4
  224. package/dist/types/src/core/dwn-error.d.ts.map +1 -1
  225. package/dist/types/src/core/grant-authorization.d.ts +5 -5
  226. package/dist/types/src/core/grant-authorization.d.ts.map +1 -1
  227. package/dist/types/src/core/message-reply.d.ts +5 -4
  228. package/dist/types/src/core/message-reply.d.ts.map +1 -1
  229. package/dist/types/src/core/messages-grant-authorization.d.ts +12 -14
  230. package/dist/types/src/core/messages-grant-authorization.d.ts.map +1 -1
  231. package/dist/types/src/core/protocol-authorization-action.d.ts +4 -5
  232. package/dist/types/src/core/protocol-authorization-action.d.ts.map +1 -1
  233. package/dist/types/src/core/protocol-authorization-validation.d.ts +13 -16
  234. package/dist/types/src/core/protocol-authorization-validation.d.ts.map +1 -1
  235. package/dist/types/src/core/protocol-authorization.d.ts +8 -33
  236. package/dist/types/src/core/protocol-authorization.d.ts.map +1 -1
  237. package/dist/types/src/core/protocols-grant-authorization.d.ts +4 -4
  238. package/dist/types/src/core/protocols-grant-authorization.d.ts.map +1 -1
  239. package/dist/types/src/core/recording-validation-state-reader.d.ts +75 -0
  240. package/dist/types/src/core/recording-validation-state-reader.d.ts.map +1 -0
  241. package/dist/types/src/core/records-grant-authorization.d.ts +8 -8
  242. package/dist/types/src/core/records-grant-authorization.d.ts.map +1 -1
  243. package/dist/types/src/core/replication-apply.d.ts +36 -0
  244. package/dist/types/src/core/replication-apply.d.ts.map +1 -1
  245. package/dist/types/src/core/resumable-task-manager.d.ts +1 -1
  246. package/dist/types/src/core/resumable-task-manager.d.ts.map +1 -1
  247. package/dist/types/src/core/validation-state-reader.d.ts +79 -0
  248. package/dist/types/src/core/validation-state-reader.d.ts.map +1 -0
  249. package/dist/types/src/dwn.d.ts +33 -20
  250. package/dist/types/src/dwn.d.ts.map +1 -1
  251. package/dist/types/src/enums/dwn-interface-method.d.ts +0 -1
  252. package/dist/types/src/enums/dwn-interface-method.d.ts.map +1 -1
  253. package/dist/types/src/event-stream/durable-event-log.d.ts +69 -0
  254. package/dist/types/src/event-stream/durable-event-log.d.ts.map +1 -0
  255. package/dist/types/src/event-stream/event-emitter-wake-publisher.d.ts +13 -0
  256. package/dist/types/src/event-stream/event-emitter-wake-publisher.d.ts.map +1 -0
  257. package/dist/types/src/handlers/messages-query.d.ts +20 -0
  258. package/dist/types/src/handlers/messages-query.d.ts.map +1 -0
  259. package/dist/types/src/handlers/messages-read.d.ts +1 -1
  260. package/dist/types/src/handlers/messages-read.d.ts.map +1 -1
  261. package/dist/types/src/handlers/messages-subscribe.d.ts.map +1 -1
  262. package/dist/types/src/handlers/protocols-configure.d.ts +0 -5
  263. package/dist/types/src/handlers/protocols-configure.d.ts.map +1 -1
  264. package/dist/types/src/handlers/records-count.d.ts +2 -1
  265. package/dist/types/src/handlers/records-count.d.ts.map +1 -1
  266. package/dist/types/src/handlers/records-delete.d.ts +2 -2
  267. package/dist/types/src/handlers/records-delete.d.ts.map +1 -1
  268. package/dist/types/src/handlers/records-query.d.ts +1 -1
  269. package/dist/types/src/handlers/records-query.d.ts.map +1 -1
  270. package/dist/types/src/handlers/records-read.d.ts +2 -1
  271. package/dist/types/src/handlers/records-read.d.ts.map +1 -1
  272. package/dist/types/src/handlers/records-subscribe.d.ts +4 -5
  273. package/dist/types/src/handlers/records-subscribe.d.ts.map +1 -1
  274. package/dist/types/src/handlers/records-write.d.ts +3 -11
  275. package/dist/types/src/handlers/records-write.d.ts.map +1 -1
  276. package/dist/types/src/index.d.ts +14 -16
  277. package/dist/types/src/index.d.ts.map +1 -1
  278. package/dist/types/src/interfaces/messages-query.d.ts +23 -0
  279. package/dist/types/src/interfaces/messages-query.d.ts.map +1 -0
  280. package/dist/types/src/interfaces/protocols-configure.d.ts +3 -3
  281. package/dist/types/src/interfaces/protocols-configure.d.ts.map +1 -1
  282. package/dist/types/src/interfaces/protocols-query.d.ts +2 -2
  283. package/dist/types/src/interfaces/protocols-query.d.ts.map +1 -1
  284. package/dist/types/src/interfaces/records-count.d.ts +3 -3
  285. package/dist/types/src/interfaces/records-count.d.ts.map +1 -1
  286. package/dist/types/src/interfaces/records-delete.d.ts +11 -3
  287. package/dist/types/src/interfaces/records-delete.d.ts.map +1 -1
  288. package/dist/types/src/interfaces/records-query.d.ts +3 -3
  289. package/dist/types/src/interfaces/records-query.d.ts.map +1 -1
  290. package/dist/types/src/interfaces/records-read.d.ts +3 -3
  291. package/dist/types/src/interfaces/records-read.d.ts.map +1 -1
  292. package/dist/types/src/interfaces/records-subscribe.d.ts +3 -3
  293. package/dist/types/src/interfaces/records-subscribe.d.ts.map +1 -1
  294. package/dist/types/src/interfaces/records-write.d.ts +15 -7
  295. package/dist/types/src/interfaces/records-write.d.ts.map +1 -1
  296. package/dist/types/src/protocols/permissions.d.ts +9 -12
  297. package/dist/types/src/protocols/permissions.d.ts.map +1 -1
  298. package/dist/types/src/store/index-level.d.ts +10 -1
  299. package/dist/types/src/store/index-level.d.ts.map +1 -1
  300. package/dist/types/src/store/level-wrapper.d.ts +5 -0
  301. package/dist/types/src/store/level-wrapper.d.ts.map +1 -1
  302. package/dist/types/src/store/message-store-level.d.ts +94 -14
  303. package/dist/types/src/store/message-store-level.d.ts.map +1 -1
  304. package/dist/types/src/store/storage-controller.d.ts +17 -14
  305. package/dist/types/src/store/storage-controller.d.ts.map +1 -1
  306. package/dist/types/src/types/message-store.d.ts +29 -1
  307. package/dist/types/src/types/message-store.d.ts.map +1 -1
  308. package/dist/types/src/types/message-types.d.ts +2 -0
  309. package/dist/types/src/types/message-types.d.ts.map +1 -1
  310. package/dist/types/src/types/messages-types.d.ts +21 -37
  311. package/dist/types/src/types/messages-types.d.ts.map +1 -1
  312. package/dist/types/src/types/method-handler.d.ts +2 -2
  313. package/dist/types/src/types/method-handler.d.ts.map +1 -1
  314. package/dist/types/src/types/permission-types.d.ts +1 -1
  315. package/dist/types/src/types/subscriptions.d.ts +50 -39
  316. package/dist/types/src/types/subscriptions.d.ts.map +1 -1
  317. package/dist/types/src/types/validation-state-reader.d.ts +116 -0
  318. package/dist/types/src/types/validation-state-reader.d.ts.map +1 -0
  319. package/dist/types/src/utils/messages.d.ts +10 -0
  320. package/dist/types/src/utils/messages.d.ts.map +1 -1
  321. package/dist/types/src/utils/record-limit-occupancy.d.ts +40 -0
  322. package/dist/types/src/utils/record-limit-occupancy.d.ts.map +1 -0
  323. package/dist/types/src/utils/records.d.ts +25 -3
  324. package/dist/types/src/utils/records.d.ts.map +1 -1
  325. package/dist/types/src/utils/replication.d.ts +22 -0
  326. package/dist/types/src/utils/replication.d.ts.map +1 -0
  327. package/dist/types/tests/core/process-message-parity.spec.d.ts +2 -0
  328. package/dist/types/tests/core/process-message-parity.spec.d.ts.map +1 -0
  329. package/dist/types/tests/core/replication-replay-property.spec.d.ts +2 -0
  330. package/dist/types/tests/core/replication-replay-property.spec.d.ts.map +1 -0
  331. package/dist/types/tests/core/validation-read-closure.spec.d.ts +2 -0
  332. package/dist/types/tests/core/validation-read-closure.spec.d.ts.map +1 -0
  333. package/dist/types/tests/core/validation-state-reader.spec.d.ts +2 -0
  334. package/dist/types/tests/core/validation-state-reader.spec.d.ts.map +1 -0
  335. package/dist/types/tests/durable-event-log.spec.d.ts +2 -0
  336. package/dist/types/tests/durable-event-log.spec.d.ts.map +1 -0
  337. package/dist/types/tests/dwn.spec.d.ts.map +1 -1
  338. package/dist/types/tests/features/author-delegated-grant.spec.d.ts.map +1 -1
  339. package/dist/types/tests/features/owner-delegated-grant.spec.d.ts.map +1 -1
  340. package/dist/types/tests/features/owner-signature.spec.d.ts.map +1 -1
  341. package/dist/types/tests/features/permissions.spec.d.ts.map +1 -1
  342. package/dist/types/tests/features/protocol-composition.spec.d.ts.map +1 -1
  343. package/dist/types/tests/features/protocol-create-action.spec.d.ts.map +1 -1
  344. package/dist/types/tests/features/protocol-delete-action.spec.d.ts.map +1 -1
  345. package/dist/types/tests/features/protocol-update-action.spec.d.ts.map +1 -1
  346. package/dist/types/tests/features/records-delivery.spec.d.ts.map +1 -1
  347. package/dist/types/tests/features/records-immutable.spec.d.ts.map +1 -1
  348. package/dist/types/tests/features/records-nested-query-scope.spec.d.ts +2 -0
  349. package/dist/types/tests/features/records-nested-query-scope.spec.d.ts.map +1 -0
  350. package/dist/types/tests/features/records-prune-cross-protocol.spec.d.ts.map +1 -1
  351. package/dist/types/tests/features/records-prune.spec.d.ts.map +1 -1
  352. package/dist/types/tests/features/records-record-limit.spec.d.ts.map +1 -1
  353. package/dist/types/tests/features/records-squash.spec.d.ts.map +1 -1
  354. package/dist/types/tests/features/records-tags.spec.d.ts.map +1 -1
  355. package/dist/types/tests/features/resumable-tasks.spec.d.ts.map +1 -1
  356. package/dist/types/tests/handlers/messages-query.spec.d.ts +2 -0
  357. package/dist/types/tests/handlers/messages-query.spec.d.ts.map +1 -0
  358. package/dist/types/tests/handlers/messages-read.spec.d.ts.map +1 -1
  359. package/dist/types/tests/handlers/messages-subscribe.spec.d.ts.map +1 -1
  360. package/dist/types/tests/handlers/protocols-configure.spec.d.ts.map +1 -1
  361. package/dist/types/tests/handlers/protocols-query.spec.d.ts.map +1 -1
  362. package/dist/types/tests/handlers/records-count.spec.d.ts.map +1 -1
  363. package/dist/types/tests/handlers/records-delete.spec.d.ts.map +1 -1
  364. package/dist/types/tests/handlers/records-query.spec.d.ts.map +1 -1
  365. package/dist/types/tests/handlers/records-read.spec.d.ts.map +1 -1
  366. package/dist/types/tests/handlers/records-subscribe.spec.d.ts.map +1 -1
  367. package/dist/types/tests/handlers/records-write.spec.d.ts.map +1 -1
  368. package/dist/types/tests/scenarios/deleted-record.spec.d.ts.map +1 -1
  369. package/dist/types/tests/scenarios/end-to-end-tests.spec.d.ts.map +1 -1
  370. package/dist/types/tests/scenarios/nested-roles.spec.d.ts.map +1 -1
  371. package/dist/types/tests/scenarios/subscriptions.spec.d.ts.map +1 -1
  372. package/dist/types/tests/store/message-store.spec.d.ts.map +1 -1
  373. package/dist/types/tests/test-event-stream.d.ts +1 -1
  374. package/dist/types/tests/test-event-stream.d.ts.map +1 -1
  375. package/dist/types/tests/test-stores.d.ts +5 -4
  376. package/dist/types/tests/test-stores.d.ts.map +1 -1
  377. package/dist/types/tests/test-suite.d.ts +1 -2
  378. package/dist/types/tests/test-suite.d.ts.map +1 -1
  379. package/dist/types/tests/utils/test-data-generator.d.ts +20 -1
  380. package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -1
  381. package/dist/types/tests/utils/test-validation-state-reader.d.ts +15 -0
  382. package/dist/types/tests/utils/test-validation-state-reader.d.ts.map +1 -0
  383. package/package.json +2 -2
  384. package/src/core/core-protocol.ts +3 -3
  385. package/src/core/dwn-constant.ts +7 -1
  386. package/src/core/dwn-error.ts +12 -4
  387. package/src/core/grant-authorization.ts +11 -20
  388. package/src/core/message-reply.ts +6 -5
  389. package/src/core/messages-grant-authorization.ts +37 -70
  390. package/src/core/protocol-authorization-action.ts +29 -38
  391. package/src/core/protocol-authorization-validation.ts +39 -96
  392. package/src/core/protocol-authorization.ts +56 -202
  393. package/src/core/protocols-grant-authorization.ts +9 -9
  394. package/src/core/recording-validation-state-reader.ts +130 -0
  395. package/src/core/records-grant-authorization.ts +16 -16
  396. package/src/core/replication-apply.ts +172 -32
  397. package/src/core/resumable-task-manager.ts +10 -8
  398. package/src/core/validation-state-reader.ts +350 -0
  399. package/src/dwn.ts +285 -192
  400. package/src/enums/dwn-interface-method.ts +0 -1
  401. package/src/event-stream/durable-event-log.ts +509 -0
  402. package/src/event-stream/event-emitter-wake-publisher.ts +34 -0
  403. package/src/handlers/messages-query.ts +203 -0
  404. package/src/handlers/messages-read.ts +9 -10
  405. package/src/handlers/messages-subscribe.ts +12 -13
  406. package/src/handlers/protocols-configure.ts +37 -58
  407. package/src/handlers/protocols-query.ts +1 -1
  408. package/src/handlers/records-count.ts +24 -17
  409. package/src/handlers/records-delete.ts +29 -27
  410. package/src/handlers/records-query.ts +38 -17
  411. package/src/handlers/records-read.ts +63 -50
  412. package/src/handlers/records-subscribe.ts +132 -19
  413. package/src/handlers/records-write.ts +77 -168
  414. package/src/index.ts +14 -17
  415. package/src/interfaces/messages-query.ts +70 -0
  416. package/src/interfaces/protocols-configure.ts +12 -4
  417. package/src/interfaces/protocols-query.ts +4 -5
  418. package/src/interfaces/records-count.ts +9 -4
  419. package/src/interfaces/records-delete.ts +25 -5
  420. package/src/interfaces/records-query.ts +9 -4
  421. package/src/interfaces/records-read.ts +4 -4
  422. package/src/interfaces/records-subscribe.ts +9 -4
  423. package/src/interfaces/records-write.ts +41 -13
  424. package/src/protocols/permissions.ts +32 -52
  425. package/src/store/index-level.ts +30 -9
  426. package/src/store/level-wrapper.ts +9 -1
  427. package/src/store/message-store-level.ts +757 -47
  428. package/src/store/storage-controller.ts +74 -63
  429. package/src/types/message-store.ts +45 -2
  430. package/src/types/message-types.ts +3 -1
  431. package/src/types/messages-types.ts +26 -45
  432. package/src/types/method-handler.ts +3 -3
  433. package/src/types/permission-types.ts +1 -1
  434. package/src/types/subscriptions.ts +53 -42
  435. package/src/types/validation-state-reader.ts +127 -0
  436. package/src/utils/messages.ts +25 -1
  437. package/src/utils/record-limit-occupancy.ts +377 -0
  438. package/src/utils/records.ts +69 -13
  439. package/src/utils/replication.ts +122 -0
  440. package/dist/esm/src/core/record-chain.js +0 -64
  441. package/dist/esm/src/core/record-chain.js.map +0 -1
  442. package/dist/esm/src/event-stream/event-emitter-event-log.js +0 -334
  443. package/dist/esm/src/event-stream/event-emitter-event-log.js.map +0 -1
  444. package/dist/esm/src/handlers/messages-sync.js +0 -278
  445. package/dist/esm/src/handlers/messages-sync.js.map +0 -1
  446. package/dist/esm/src/interfaces/messages-sync.js.map +0 -1
  447. package/dist/esm/src/smt/smt-store-level.js +0 -103
  448. package/dist/esm/src/smt/smt-store-level.js.map +0 -1
  449. package/dist/esm/src/smt/smt-store-memory.js +0 -41
  450. package/dist/esm/src/smt/smt-store-memory.js.map +0 -1
  451. package/dist/esm/src/smt/smt-utils.js +0 -129
  452. package/dist/esm/src/smt/smt-utils.js.map +0 -1
  453. package/dist/esm/src/smt/sparse-merkle-tree.js +0 -577
  454. package/dist/esm/src/smt/sparse-merkle-tree.js.map +0 -1
  455. package/dist/esm/src/state-index/state-index-level.js +0 -191
  456. package/dist/esm/src/state-index/state-index-level.js.map +0 -1
  457. package/dist/esm/src/types/smt-types.js +0 -5
  458. package/dist/esm/src/types/smt-types.js.map +0 -1
  459. package/dist/esm/src/types/state-index.js +0 -2
  460. package/dist/esm/src/types/state-index.js.map +0 -1
  461. package/dist/esm/tests/event-emitter-event-log.spec.js +0 -499
  462. package/dist/esm/tests/event-emitter-event-log.spec.js.map +0 -1
  463. package/dist/esm/tests/handlers/messages-sync.spec.js +0 -1088
  464. package/dist/esm/tests/handlers/messages-sync.spec.js.map +0 -1
  465. package/dist/esm/tests/smt/smt-store-level.spec.js +0 -132
  466. package/dist/esm/tests/smt/smt-store-level.spec.js.map +0 -1
  467. package/dist/esm/tests/smt/sparse-merkle-tree.spec.js +0 -732
  468. package/dist/esm/tests/smt/sparse-merkle-tree.spec.js.map +0 -1
  469. package/dist/esm/tests/state-index/state-index-level.spec.js +0 -245
  470. package/dist/esm/tests/state-index/state-index-level.spec.js.map +0 -1
  471. package/dist/types/src/core/record-chain.d.ts +0 -24
  472. package/dist/types/src/core/record-chain.d.ts.map +0 -1
  473. package/dist/types/src/event-stream/event-emitter-event-log.d.ts +0 -80
  474. package/dist/types/src/event-stream/event-emitter-event-log.d.ts.map +0 -1
  475. package/dist/types/src/handlers/messages-sync.d.ts +0 -39
  476. package/dist/types/src/handlers/messages-sync.d.ts.map +0 -1
  477. package/dist/types/src/interfaces/messages-sync.d.ts +0 -20
  478. package/dist/types/src/interfaces/messages-sync.d.ts.map +0 -1
  479. package/dist/types/src/smt/smt-store-level.d.ts +0 -32
  480. package/dist/types/src/smt/smt-store-level.d.ts.map +0 -1
  481. package/dist/types/src/smt/smt-store-memory.d.ts +0 -22
  482. package/dist/types/src/smt/smt-store-memory.d.ts.map +0 -1
  483. package/dist/types/src/smt/smt-utils.d.ts +0 -58
  484. package/dist/types/src/smt/smt-utils.d.ts.map +0 -1
  485. package/dist/types/src/smt/sparse-merkle-tree.d.ts +0 -124
  486. package/dist/types/src/smt/sparse-merkle-tree.d.ts.map +0 -1
  487. package/dist/types/src/state-index/state-index-level.d.ts +0 -83
  488. package/dist/types/src/state-index/state-index-level.d.ts.map +0 -1
  489. package/dist/types/src/types/smt-types.d.ts +0 -81
  490. package/dist/types/src/types/smt-types.d.ts.map +0 -1
  491. package/dist/types/src/types/state-index.d.ts +0 -90
  492. package/dist/types/src/types/state-index.d.ts.map +0 -1
  493. package/dist/types/tests/event-emitter-event-log.spec.d.ts +0 -2
  494. package/dist/types/tests/event-emitter-event-log.spec.d.ts.map +0 -1
  495. package/dist/types/tests/handlers/messages-sync.spec.d.ts +0 -2
  496. package/dist/types/tests/handlers/messages-sync.spec.d.ts.map +0 -1
  497. package/dist/types/tests/smt/smt-store-level.spec.d.ts +0 -2
  498. package/dist/types/tests/smt/smt-store-level.spec.d.ts.map +0 -1
  499. package/dist/types/tests/smt/sparse-merkle-tree.spec.d.ts +0 -2
  500. package/dist/types/tests/smt/sparse-merkle-tree.spec.d.ts.map +0 -1
  501. package/dist/types/tests/state-index/state-index-level.spec.d.ts +0 -2
  502. package/dist/types/tests/state-index/state-index-level.spec.d.ts.map +0 -1
  503. package/src/core/record-chain.ts +0 -99
  504. package/src/event-stream/event-emitter-event-log.ts +0 -430
  505. package/src/handlers/messages-sync.ts +0 -403
  506. package/src/interfaces/messages-sync.ts +0 -69
  507. package/src/smt/smt-store-level.ts +0 -143
  508. package/src/smt/smt-store-memory.ts +0 -53
  509. package/src/smt/smt-utils.ts +0 -149
  510. package/src/smt/sparse-merkle-tree.ts +0 -698
  511. package/src/state-index/state-index-level.ts +0 -239
  512. package/src/types/smt-types.ts +0 -95
  513. package/src/types/state-index.ts +0 -100
@@ -1,1088 +0,0 @@
1
- import freeForAll from '../vectors/protocol-definitions/free-for-all.json' with { type: 'json' };
2
- import { Jws } from '../../src/utils/jws.js';
3
- import { KEY_DELIVERY_PROTOCOL_URI } from '../../src/core/constants.js';
4
- import { Message } from '../../src/core/message.js';
5
- import { MessagesSync } from '../../src/interfaces/messages-sync.js';
6
- import { MessagesSyncHandler } from '../../src/handlers/messages-sync.js';
7
- import sinon from 'sinon';
8
- import { TestDataGenerator } from '../utils/test-data-generator.js';
9
- import { TestEventLog } from '../test-event-stream.js';
10
- import { TestStores } from '../test-stores.js';
11
- import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'bun:test';
12
- import { DataStream, Dwn, DwnErrorCode, DwnInterfaceName, DwnMethodName, Encoder, PermissionGrant, PermissionsProtocol, Time } from '../../src/index.js';
13
- import { DidKey, UniversalResolver } from '@enbox/dids';
14
- export function testMessagesSyncHandler() {
15
- describe('MessagesSyncHandler.handle()', () => {
16
- let didResolver;
17
- let messageStore;
18
- let dataStore;
19
- let resumableTaskStore;
20
- let stateIndex;
21
- let eventLog;
22
- let dwn;
23
- beforeAll(async () => {
24
- didResolver = new UniversalResolver({ didResolvers: [DidKey] });
25
- const stores = TestStores.get();
26
- messageStore = stores.messageStore;
27
- dataStore = stores.dataStore;
28
- resumableTaskStore = stores.resumableTaskStore;
29
- stateIndex = stores.stateIndex;
30
- eventLog = TestEventLog.get();
31
- dwn = await Dwn.create({ didResolver, messageStore, dataStore, stateIndex, eventLog, resumableTaskStore });
32
- });
33
- beforeEach(async () => {
34
- await messageStore.clear();
35
- await dataStore.clear();
36
- await resumableTaskStore.clear();
37
- await stateIndex.clear();
38
- });
39
- afterAll(async () => {
40
- await dwn.close();
41
- });
42
- describe('root action', () => {
43
- it('returns the empty root hash for a tenant with no messages', async () => {
44
- const alice = await TestDataGenerator.generateDidKeyPersona();
45
- const { message } = await MessagesSync.create({
46
- signer: Jws.createSigner(alice),
47
- action: 'root',
48
- });
49
- const reply = await dwn.processMessage(alice.did, message);
50
- expect(reply.status.code).toBe(200);
51
- expect(typeof reply.root).toBe('string');
52
- expect(reply.root.length).toBe(64); // hex-encoded 32-byte hash
53
- });
54
- it('returns a different root hash after writing a message', async () => {
55
- const alice = await TestDataGenerator.generateDidKeyPersona();
56
- await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
57
- // get the empty root
58
- const { message: rootMsg1 } = await MessagesSync.create({
59
- signer: Jws.createSigner(alice),
60
- action: 'root',
61
- });
62
- const reply1 = await dwn.processMessage(alice.did, rootMsg1);
63
- expect(reply1.status.code).toBe(200);
64
- const emptyRoot = reply1.root;
65
- // write a record
66
- const { message: recordMessage, dataStream } = await TestDataGenerator.generateRecordsWrite({ author: alice });
67
- const writeReply = await dwn.processMessage(alice.did, recordMessage, { dataStream });
68
- expect(writeReply.status.code).toBe(202);
69
- // get the root again
70
- const { message: rootMsg2 } = await MessagesSync.create({
71
- signer: Jws.createSigner(alice),
72
- action: 'root',
73
- });
74
- const reply2 = await dwn.processMessage(alice.did, rootMsg2);
75
- expect(reply2.status.code).toBe(200);
76
- expect(reply2.root).not.toBe(emptyRoot);
77
- });
78
- it('returns protocol-scoped root hash when protocol is specified', async () => {
79
- const alice = await TestDataGenerator.generateDidKeyPersona();
80
- await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
81
- const protocolDefinition = { ...freeForAll, published: true };
82
- // configure the protocol
83
- const { message: protocolMessage } = await TestDataGenerator.generateProtocolsConfigure({
84
- author: alice,
85
- protocolDefinition,
86
- });
87
- const configureReply = await dwn.processMessage(alice.did, protocolMessage);
88
- expect(configureReply.status.code).toBe(202);
89
- // write a record for this protocol
90
- const { message: recordMessage, dataStream } = await TestDataGenerator.generateRecordsWrite({
91
- author: alice,
92
- protocol: protocolDefinition.protocol,
93
- protocolPath: 'post',
94
- schema: protocolDefinition.types.post.schema,
95
- });
96
- const writeReply = await dwn.processMessage(alice.did, recordMessage, { dataStream });
97
- expect(writeReply.status.code).toBe(202);
98
- // write a record under a different protocol to diverge the global root
99
- const { message: otherRecord, dataStream: otherDataStream } = await TestDataGenerator.generateRecordsWrite({ author: alice });
100
- const otherWriteReply = await dwn.processMessage(alice.did, otherRecord, { dataStream: otherDataStream });
101
- expect(otherWriteReply.status.code).toBe(202);
102
- // get the global root
103
- const { message: globalRootMsg } = await MessagesSync.create({
104
- signer: Jws.createSigner(alice),
105
- action: 'root',
106
- });
107
- const globalReply = await dwn.processMessage(alice.did, globalRootMsg);
108
- expect(globalReply.status.code).toBe(200);
109
- // get the protocol-scoped root
110
- const { message: protoRootMsg } = await MessagesSync.create({
111
- signer: Jws.createSigner(alice),
112
- action: 'root',
113
- protocol: protocolDefinition.protocol,
114
- });
115
- const protoReply = await dwn.processMessage(alice.did, protoRootMsg);
116
- expect(protoReply.status.code).toBe(200);
117
- // global root and protocol root should be different
118
- // (global includes the record from the other protocol)
119
- expect(protoReply.root).not.toBe(globalReply.root);
120
- // both should be non-empty roots
121
- expect(protoReply.root.length).toBe(64);
122
- });
123
- });
124
- describe('subtree action', () => {
125
- it('returns a subtree hash for a given bit prefix', async () => {
126
- const alice = await TestDataGenerator.generateDidKeyPersona();
127
- await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
128
- // write a record so the tree is non-empty
129
- const { message: recordMessage, dataStream } = await TestDataGenerator.generateRecordsWrite({ author: alice });
130
- const writeReply = await dwn.processMessage(alice.did, recordMessage, { dataStream });
131
- expect(writeReply.status.code).toBe(202);
132
- const { message } = await MessagesSync.create({
133
- signer: Jws.createSigner(alice),
134
- action: 'subtree',
135
- prefix: '0',
136
- });
137
- const reply = await dwn.processMessage(alice.did, message);
138
- expect(reply.status.code).toBe(200);
139
- expect(typeof reply.hash).toBe('string');
140
- expect(reply.hash.length).toBe(64);
141
- });
142
- it('returns different hashes for different prefixes', async () => {
143
- const alice = await TestDataGenerator.generateDidKeyPersona();
144
- await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
145
- // write several records to populate various subtrees
146
- for (let i = 0; i < 10; i++) {
147
- const { message: recordMessage, dataStream } = await TestDataGenerator.generateRecordsWrite({ author: alice });
148
- const writeReply = await dwn.processMessage(alice.did, recordMessage, { dataStream });
149
- expect(writeReply.status.code).toBe(202);
150
- }
151
- const { message: msg0 } = await MessagesSync.create({
152
- signer: Jws.createSigner(alice),
153
- action: 'subtree',
154
- prefix: '0',
155
- });
156
- const reply0 = await dwn.processMessage(alice.did, msg0);
157
- const { message: msg1 } = await MessagesSync.create({
158
- signer: Jws.createSigner(alice),
159
- action: 'subtree',
160
- prefix: '1',
161
- });
162
- const reply1 = await dwn.processMessage(alice.did, msg1);
163
- expect(reply0.status.code).toBe(200);
164
- expect(reply1.status.code).toBe(200);
165
- // With 10 messages, it's very likely the two halves of the tree differ
166
- // (not guaranteed but probabilistically near-certain)
167
- });
168
- });
169
- describe('leaves action', () => {
170
- it('returns all message CIDs for an empty prefix', async () => {
171
- const alice = await TestDataGenerator.generateDidKeyPersona();
172
- await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
173
- // write some messages
174
- const expectedCids = [];
175
- for (let i = 0; i < 3; i++) {
176
- const { message: recordMessage, dataStream } = await TestDataGenerator.generateRecordsWrite({ author: alice });
177
- const writeReply = await dwn.processMessage(alice.did, recordMessage, { dataStream });
178
- expect(writeReply.status.code).toBe(202);
179
- expectedCids.push(await Message.getCid(recordMessage));
180
- }
181
- const { message } = await MessagesSync.create({
182
- signer: Jws.createSigner(alice),
183
- action: 'leaves',
184
- prefix: '',
185
- });
186
- const reply = await dwn.processMessage(alice.did, message);
187
- expect(reply.status.code).toBe(200);
188
- expect(Array.isArray(reply.entries)).toBe(true);
189
- // 3 RecordsWrite messages + 1 ProtocolsConfigure for the default test protocol
190
- expect(reply.entries.length).toBe(4);
191
- for (const cid of expectedCids) {
192
- expect(reply.entries).toContain(cid);
193
- }
194
- });
195
- it('returns protocol-scoped leaves when protocol is specified', async () => {
196
- const alice = await TestDataGenerator.generateDidKeyPersona();
197
- await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
198
- const protocolDefinition = { ...freeForAll, published: true };
199
- // configure the protocol
200
- const { message: protocolMessage } = await TestDataGenerator.generateProtocolsConfigure({
201
- author: alice,
202
- protocolDefinition,
203
- });
204
- const configureReply = await dwn.processMessage(alice.did, protocolMessage);
205
- expect(configureReply.status.code).toBe(202);
206
- // write a protocol-scoped record
207
- const { message: protoRecord, dataStream: protoDataStream } = await TestDataGenerator.generateRecordsWrite({
208
- author: alice,
209
- protocol: protocolDefinition.protocol,
210
- protocolPath: 'post',
211
- schema: protocolDefinition.types.post.schema,
212
- });
213
- const protoWriteReply = await dwn.processMessage(alice.did, protoRecord, { dataStream: protoDataStream });
214
- expect(protoWriteReply.status.code).toBe(202);
215
- // write a record under a different protocol
216
- const { message: otherRecord, dataStream: otherDataStream } = await TestDataGenerator.generateRecordsWrite({ author: alice });
217
- const otherWriteReply = await dwn.processMessage(alice.did, otherRecord, { dataStream: otherDataStream });
218
- expect(otherWriteReply.status.code).toBe(202);
219
- // query protocol-scoped leaves
220
- const { message } = await MessagesSync.create({
221
- signer: Jws.createSigner(alice),
222
- action: 'leaves',
223
- prefix: '',
224
- protocol: protocolDefinition.protocol,
225
- });
226
- const reply = await dwn.processMessage(alice.did, message);
227
- expect(reply.status.code).toBe(200);
228
- // should contain the ProtocolsConfigure and the protocol-scoped record, but not the other-protocol record
229
- expect(reply.entries.length).toBe(2);
230
- const protocolCid = await Message.getCid(protocolMessage);
231
- const recordCid = await Message.getCid(protoRecord);
232
- expect(reply.entries).toContain(protocolCid);
233
- expect(reply.entries).toContain(recordCid);
234
- });
235
- });
236
- describe('authorization', () => {
237
- it('returns 401 if tenant is not the author', async () => {
238
- const alice = await TestDataGenerator.generateDidKeyPersona();
239
- const bob = await TestDataGenerator.generateDidKeyPersona();
240
- const { message } = await MessagesSync.create({
241
- signer: Jws.createSigner(alice),
242
- action: 'root',
243
- });
244
- const reply = await dwn.processMessage(bob.did, message);
245
- expect(reply.status.code).toBe(401);
246
- });
247
- it('returns 400 if message is invalid', async () => {
248
- const alice = await TestDataGenerator.generateDidKeyPersona();
249
- const { message } = await MessagesSync.create({
250
- signer: Jws.createSigner(alice),
251
- action: 'root',
252
- });
253
- message['descriptor']['troll'] = 'hehe';
254
- const handler = new MessagesSyncHandler({ didResolver, messageStore, stateIndex });
255
- const reply = await handler.handle({ tenant: alice.did, message });
256
- expect(reply.status.code).toBe(400);
257
- });
258
- describe('grant-based sync', () => {
259
- it('allows sync with a matching MessagesSync grant scope', async () => {
260
- const alice = await TestDataGenerator.generateDidKeyPersona();
261
- const bob = await TestDataGenerator.generateDidKeyPersona();
262
- await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
263
- // write a record so the tree is non-empty
264
- const { message: recordMessage, dataStream } = await TestDataGenerator.generateRecordsWrite({ author: alice });
265
- const writeReply = await dwn.processMessage(alice.did, recordMessage, { dataStream });
266
- expect(writeReply.status.code).toBe(202);
267
- // grant bob permission to sync Alice's messages
268
- const { message: grantMessage, dataStream: grantDataStream } = await TestDataGenerator.generateGrantCreate({
269
- author: alice,
270
- grantedTo: bob,
271
- scope: {
272
- interface: DwnInterfaceName.Messages,
273
- method: DwnMethodName.Read,
274
- },
275
- });
276
- const grantReply = await dwn.processMessage(alice.did, grantMessage, { dataStream: grantDataStream });
277
- expect(grantReply.status.code).toBe(202);
278
- // bob syncs using the grant — root action
279
- const { message: syncMsg } = await MessagesSync.create({
280
- signer: Jws.createSigner(bob),
281
- action: 'root',
282
- permissionGrantIds: [grantMessage.recordId],
283
- });
284
- const reply = await dwn.processMessage(alice.did, syncMsg);
285
- expect(reply.status.code).toBe(200);
286
- expect(typeof reply.root).toBe('string');
287
- expect(reply.root.length).toBe(64);
288
- });
289
- it('allows sync with a unified MessagesRead grant scope', async () => {
290
- // scenario: A Messages.Read grant should also authorize MessagesSync operations
291
- const alice = await TestDataGenerator.generateDidKeyPersona();
292
- const bob = await TestDataGenerator.generateDidKeyPersona();
293
- await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
294
- // write a record so the tree is non-empty
295
- const { message: recordMessage, dataStream } = await TestDataGenerator.generateRecordsWrite({ author: alice });
296
- const writeReply = await dwn.processMessage(alice.did, recordMessage, { dataStream });
297
- expect(writeReply.status.code).toBe(202);
298
- // grant bob permission with Messages.Read scope (unified)
299
- const { message: grantMessage, dataStream: grantDataStream } = await TestDataGenerator.generateGrantCreate({
300
- author: alice,
301
- grantedTo: bob,
302
- scope: {
303
- interface: DwnInterfaceName.Messages,
304
- method: DwnMethodName.Read,
305
- },
306
- });
307
- const grantReply = await dwn.processMessage(alice.did, grantMessage, { dataStream: grantDataStream });
308
- expect(grantReply.status.code).toBe(202);
309
- // bob syncs using the Messages.Read grant — root action
310
- const { message: syncMsg } = await MessagesSync.create({
311
- signer: Jws.createSigner(bob),
312
- action: 'root',
313
- permissionGrantIds: [grantMessage.recordId],
314
- });
315
- const reply2 = await dwn.processMessage(alice.did, syncMsg);
316
- expect(reply2.status.code).toBe(200);
317
- expect(typeof reply2.root).toBe('string');
318
- expect(reply2.root.length).toBe(64);
319
- });
320
- it('allows sync with a protocol-scoped MessagesRead grant', async () => {
321
- // scenario: A Messages.Read grant scoped to a protocol should authorize protocol-scoped MessagesSync
322
- const alice = await TestDataGenerator.generateDidKeyPersona();
323
- const bob = await TestDataGenerator.generateDidKeyPersona();
324
- const protocolDefinition = { ...freeForAll, published: true };
325
- // configure and write a protocol record
326
- const { message: protocolMessage } = await TestDataGenerator.generateProtocolsConfigure({
327
- author: alice,
328
- protocolDefinition,
329
- });
330
- await dwn.processMessage(alice.did, protocolMessage);
331
- const { message: recordMessage, dataStream } = await TestDataGenerator.generateRecordsWrite({
332
- author: alice,
333
- protocol: protocolDefinition.protocol,
334
- protocolPath: 'post',
335
- schema: protocolDefinition.types.post.schema,
336
- });
337
- await dwn.processMessage(alice.did, recordMessage, { dataStream });
338
- // grant bob permission with Messages.Read scope scoped to this protocol
339
- const { message: grantMessage, dataStream: grantDataStream } = await TestDataGenerator.generateGrantCreate({
340
- author: alice,
341
- grantedTo: bob,
342
- scope: {
343
- interface: DwnInterfaceName.Messages,
344
- method: DwnMethodName.Read,
345
- protocol: protocolDefinition.protocol,
346
- },
347
- });
348
- const grantReply = await dwn.processMessage(alice.did, grantMessage, { dataStream: grantDataStream });
349
- expect(grantReply.status.code).toBe(202);
350
- // bob syncs leaves with the protocol-scoped Messages.Read grant
351
- const { message: syncMsg } = await MessagesSync.create({
352
- signer: Jws.createSigner(bob),
353
- action: 'leaves',
354
- prefix: '',
355
- protocol: protocolDefinition.protocol,
356
- permissionGrantIds: [grantMessage.recordId],
357
- });
358
- const reply2 = await dwn.processMessage(alice.did, syncMsg);
359
- expect(reply2.status.code).toBe(200);
360
- expect(Array.isArray(reply2.entries)).toBe(true);
361
- expect(reply2.entries.length).toBe(2);
362
- });
363
- it('allows sync with a protocol-scoped grant', async () => {
364
- const alice = await TestDataGenerator.generateDidKeyPersona();
365
- const bob = await TestDataGenerator.generateDidKeyPersona();
366
- const protocolDefinition = { ...freeForAll, published: true };
367
- // configure and write a protocol record
368
- const { message: protocolMessage } = await TestDataGenerator.generateProtocolsConfigure({
369
- author: alice,
370
- protocolDefinition,
371
- });
372
- await dwn.processMessage(alice.did, protocolMessage);
373
- const { message: recordMessage, dataStream } = await TestDataGenerator.generateRecordsWrite({
374
- author: alice,
375
- protocol: protocolDefinition.protocol,
376
- protocolPath: 'post',
377
- schema: protocolDefinition.types.post.schema,
378
- });
379
- await dwn.processMessage(alice.did, recordMessage, { dataStream });
380
- // grant bob permission to sync Alice's messages scoped to this protocol
381
- const { message: grantMessage, dataStream: grantDataStream } = await TestDataGenerator.generateGrantCreate({
382
- author: alice,
383
- grantedTo: bob,
384
- scope: {
385
- interface: DwnInterfaceName.Messages,
386
- method: DwnMethodName.Read,
387
- protocol: protocolDefinition.protocol,
388
- },
389
- });
390
- const grantReply = await dwn.processMessage(alice.did, grantMessage, { dataStream: grantDataStream });
391
- expect(grantReply.status.code).toBe(202);
392
- // bob syncs leaves with the protocol-scoped grant
393
- const { message: syncMsg } = await MessagesSync.create({
394
- signer: Jws.createSigner(bob),
395
- action: 'leaves',
396
- prefix: '',
397
- protocol: protocolDefinition.protocol,
398
- permissionGrantIds: [grantMessage.recordId],
399
- });
400
- const reply = await dwn.processMessage(alice.did, syncMsg);
401
- expect(reply.status.code).toBe(200);
402
- expect(Array.isArray(reply.entries)).toBe(true);
403
- // includes both the ProtocolsConfigure and the RecordsWrite
404
- expect(reply.entries.length).toBe(2);
405
- const protocolCid = await Message.getCid(protocolMessage);
406
- const recordCid = await Message.getCid(recordMessage);
407
- expect(reply.entries).toContain(protocolCid);
408
- expect(reply.entries).toContain(recordCid);
409
- });
410
- it('allows protocol sync when one grant in a plural grant set covers the protocol', async () => {
411
- const alice = await TestDataGenerator.generateDidKeyPersona();
412
- const bob = await TestDataGenerator.generateDidKeyPersona();
413
- const protocol1 = { ...freeForAll, published: true, protocol: 'http://plural-grant-sync-1' };
414
- const protocol2 = { ...freeForAll, published: true, protocol: 'http://plural-grant-sync-2' };
415
- for (const protocolDefinition of [protocol1, protocol2]) {
416
- const { message: protocolMessage } = await TestDataGenerator.generateProtocolsConfigure({
417
- author: alice,
418
- protocolDefinition,
419
- });
420
- await dwn.processMessage(alice.did, protocolMessage);
421
- }
422
- const { message: recordMessage, dataStream } = await TestDataGenerator.generateRecordsWrite({
423
- author: alice,
424
- protocol: protocol2.protocol,
425
- protocolPath: 'post',
426
- schema: protocol2.types.post.schema,
427
- });
428
- await dwn.processMessage(alice.did, recordMessage, { dataStream });
429
- const grantIds = [];
430
- for (const protocolDefinition of [protocol1, protocol2]) {
431
- const { message: grantMessage, dataStream: grantDataStream } = await TestDataGenerator.generateGrantCreate({
432
- author: alice,
433
- grantedTo: bob,
434
- scope: {
435
- interface: DwnInterfaceName.Messages,
436
- method: DwnMethodName.Read,
437
- protocol: protocolDefinition.protocol,
438
- },
439
- });
440
- const grantReply = await dwn.processMessage(alice.did, grantMessage, { dataStream: grantDataStream });
441
- expect(grantReply.status.code).toBe(202);
442
- grantIds.push(grantMessage.recordId);
443
- }
444
- const { message: syncMsg } = await MessagesSync.create({
445
- signer: Jws.createSigner(bob),
446
- action: 'leaves',
447
- prefix: '',
448
- protocol: protocol2.protocol,
449
- permissionGrantIds: grantIds.reverse(),
450
- });
451
- const reply = await dwn.processMessage(alice.did, syncMsg);
452
- expect(reply.status.code).toBe(200);
453
- expect(reply.entries).toContain(await Message.getCid(recordMessage));
454
- expect(syncMsg.descriptor.permissionGrantIds).toEqual([...grantIds].sort());
455
- });
456
- it('rejects sync when any grant in a plural grant set is expired', async () => {
457
- const alice = await TestDataGenerator.generateDidKeyPersona();
458
- const bob = await TestDataGenerator.generateDidKeyPersona();
459
- const protocol = 'http://plural-grant-sync-expired';
460
- const now = Time.getCurrentTimestamp();
461
- const { message: activeGrantMessage, dataStream: activeGrantDataStream } = await TestDataGenerator.generateGrantCreate({
462
- author: alice,
463
- grantedTo: bob,
464
- dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 }, now),
465
- scope: {
466
- interface: DwnInterfaceName.Messages,
467
- method: DwnMethodName.Read,
468
- protocol,
469
- },
470
- });
471
- expect((await dwn.processMessage(alice.did, activeGrantMessage, { dataStream: activeGrantDataStream })).status.code).toBe(202);
472
- const { message: expiredGrantMessage, dataStream: expiredGrantDataStream } = await TestDataGenerator.generateGrantCreate({
473
- author: alice,
474
- grantedTo: bob,
475
- dateGranted: Time.createOffsetTimestamp({ seconds: -120 }, now),
476
- dateExpires: Time.createOffsetTimestamp({ seconds: -60 }, now),
477
- scope: {
478
- interface: DwnInterfaceName.Messages,
479
- method: DwnMethodName.Read,
480
- protocol,
481
- },
482
- });
483
- expect((await dwn.processMessage(alice.did, expiredGrantMessage, { dataStream: expiredGrantDataStream })).status.code).toBe(202);
484
- const { message: syncMsg } = await MessagesSync.create({
485
- signer: Jws.createSigner(bob),
486
- action: 'root',
487
- protocol,
488
- permissionGrantIds: [activeGrantMessage.recordId, expiredGrantMessage.recordId],
489
- });
490
- const reply = await dwn.processMessage(alice.did, syncMsg);
491
- expect(reply.status.code).toBe(401);
492
- expect(reply.status.detail).toContain(DwnErrorCode.GrantAuthorizationGrantExpired);
493
- });
494
- it('rejects sync when any grant in a plural grant set is revoked', async () => {
495
- const alice = await TestDataGenerator.generateDidKeyPersona();
496
- const bob = await TestDataGenerator.generateDidKeyPersona();
497
- const protocol = 'http://plural-grant-sync-revoked';
498
- const { message: activeGrantMessage, dataStream: activeGrantDataStream } = await TestDataGenerator.generateGrantCreate({
499
- author: alice,
500
- grantedTo: bob,
501
- scope: {
502
- interface: DwnInterfaceName.Messages,
503
- method: DwnMethodName.Read,
504
- protocol,
505
- },
506
- });
507
- expect((await dwn.processMessage(alice.did, activeGrantMessage, { dataStream: activeGrantDataStream })).status.code).toBe(202);
508
- const revokedGrant = await TestDataGenerator.generateGrantCreate({
509
- author: alice,
510
- grantedTo: bob,
511
- scope: {
512
- interface: DwnInterfaceName.Messages,
513
- method: DwnMethodName.Read,
514
- protocol,
515
- },
516
- });
517
- expect((await dwn.processMessage(alice.did, revokedGrant.message, { dataStream: revokedGrant.dataStream })).status.code).toBe(202);
518
- const revocation = await PermissionsProtocol.createRevocation({
519
- signer: Jws.createSigner(alice),
520
- grant: PermissionGrant.parse(revokedGrant.dataEncodedMessage),
521
- });
522
- const revocationReply = await dwn.processMessage(alice.did, revocation.recordsWrite.message, { dataStream: DataStream.fromBytes(revocation.permissionRevocationBytes) });
523
- expect(revocationReply.status.code).toBe(202);
524
- await Time.minimalSleep();
525
- const { message: syncMsg } = await MessagesSync.create({
526
- signer: Jws.createSigner(bob),
527
- action: 'root',
528
- protocol,
529
- permissionGrantIds: [activeGrantMessage.recordId, revokedGrant.message.recordId],
530
- });
531
- const reply = await dwn.processMessage(alice.did, syncMsg);
532
- expect(reply.status.code).toBe(401);
533
- expect(reply.status.detail).toContain(DwnErrorCode.GrantAuthorizationGrantRevoked);
534
- });
535
- it('rejects sync with mismatching interface grant scope', async () => {
536
- const alice = await TestDataGenerator.generateDidKeyPersona();
537
- const bob = await TestDataGenerator.generateDidKeyPersona();
538
- // create a RecordsWrite grant (wrong interface for MessagesSync)
539
- const { message: grantMessage, dataStream } = await TestDataGenerator.generateGrantCreate({
540
- author: alice,
541
- grantedTo: bob,
542
- scope: {
543
- interface: DwnInterfaceName.Records,
544
- method: DwnMethodName.Write,
545
- protocol: freeForAll.protocol,
546
- },
547
- });
548
- const grantReply = await dwn.processMessage(alice.did, grantMessage, { dataStream });
549
- expect(grantReply.status.code).toBe(202);
550
- const { message: syncMsg } = await MessagesSync.create({
551
- signer: Jws.createSigner(bob),
552
- action: 'root',
553
- permissionGrantIds: [grantMessage.recordId],
554
- });
555
- const reply = await dwn.processMessage(alice.did, syncMsg);
556
- expect(reply.status.code).toBe(401);
557
- expect(reply.status.detail).toContain(DwnErrorCode.GrantAuthorizationInterfaceMismatch);
558
- });
559
- it('rejects sync with mismatching protocol grant scope', async () => {
560
- const alice = await TestDataGenerator.generateDidKeyPersona();
561
- const bob = await TestDataGenerator.generateDidKeyPersona();
562
- // grant bob permission to sync protocol1
563
- const { message: grantMessage, dataStream } = await TestDataGenerator.generateGrantCreate({
564
- author: alice,
565
- grantedTo: bob,
566
- scope: {
567
- interface: DwnInterfaceName.Messages,
568
- method: DwnMethodName.Read,
569
- protocol: 'http://protocol1',
570
- },
571
- });
572
- const grantReply = await dwn.processMessage(alice.did, grantMessage, { dataStream });
573
- expect(grantReply.status.code).toBe(202);
574
- // bob attempts to sync protocol2 using the protocol1 grant
575
- const { message: syncMsg } = await MessagesSync.create({
576
- signer: Jws.createSigner(bob),
577
- action: 'root',
578
- protocol: 'http://protocol2',
579
- permissionGrantIds: [grantMessage.recordId],
580
- });
581
- const reply = await dwn.processMessage(alice.did, syncMsg);
582
- expect(reply.status.code).toBe(401);
583
- expect(reply.status.detail).toContain(DwnErrorCode.MessagesGrantAuthorizationMismatchedProtocol);
584
- });
585
- it('rejects full-tenant sync actions with a protocol-scoped grant', async () => {
586
- const alice = await TestDataGenerator.generateDidKeyPersona();
587
- const bob = await TestDataGenerator.generateDidKeyPersona();
588
- const { message: grantMessage, dataStream } = await TestDataGenerator.generateGrantCreate({
589
- author: alice,
590
- grantedTo: bob,
591
- scope: {
592
- interface: DwnInterfaceName.Messages,
593
- method: DwnMethodName.Read,
594
- protocol: 'http://protocol-scoped-sync',
595
- },
596
- });
597
- const grantReply = await dwn.processMessage(alice.did, grantMessage, { dataStream });
598
- expect(grantReply.status.code).toBe(202);
599
- const syncActions = [
600
- { action: 'root' },
601
- { action: 'subtree', prefix: '' },
602
- { action: 'leaves', prefix: '' },
603
- { action: 'diff', hashes: {}, depth: 2 },
604
- ];
605
- for (const syncAction of syncActions) {
606
- const { message: syncMsg } = await MessagesSync.create({
607
- signer: Jws.createSigner(bob),
608
- ...syncAction,
609
- permissionGrantIds: [grantMessage.recordId],
610
- });
611
- const reply = await dwn.processMessage(alice.did, syncMsg);
612
- expect(reply.status.code).toBe(401);
613
- expect(reply.status.detail).toContain(DwnErrorCode.MessagesGrantAuthorizationMismatchedProtocol);
614
- }
615
- });
616
- it('rejects protocol sync with subtree-scoped grants', async () => {
617
- const alice = await TestDataGenerator.generateDidKeyPersona();
618
- const bob = await TestDataGenerator.generateDidKeyPersona();
619
- const protocol = 'http://subtree-scoped-sync';
620
- const scopedGrants = [
621
- {
622
- interface: DwnInterfaceName.Messages,
623
- method: DwnMethodName.Read,
624
- protocol,
625
- protocolPath: 'post',
626
- },
627
- {
628
- interface: DwnInterfaceName.Messages,
629
- method: DwnMethodName.Read,
630
- protocol,
631
- contextId: 'root',
632
- },
633
- ];
634
- for (const scope of scopedGrants) {
635
- const { message: grantMessage, dataStream } = await TestDataGenerator.generateGrantCreate({
636
- author: alice,
637
- grantedTo: bob,
638
- scope,
639
- });
640
- const grantReply = await dwn.processMessage(alice.did, grantMessage, { dataStream });
641
- expect(grantReply.status.code).toBe(202);
642
- const { message: syncMsg } = await MessagesSync.create({
643
- signer: Jws.createSigner(bob),
644
- action: 'root',
645
- protocol,
646
- permissionGrantIds: [grantMessage.recordId],
647
- });
648
- const reply = await dwn.processMessage(alice.did, syncMsg);
649
- expect(reply.status.code).toBe(401);
650
- expect(reply.status.detail).toContain(DwnErrorCode.MessagesGrantAuthorizationMismatchedProtocol);
651
- }
652
- });
653
- it('rejects delegated MessagesSync of infrastructure protocols', async () => {
654
- const alice = await TestDataGenerator.generateDidKeyPersona();
655
- const bob = await TestDataGenerator.generateDidKeyPersona();
656
- const carol = await TestDataGenerator.generateDidKeyPersona();
657
- const { message: permissionsGrantMessage, dataStream: permissionsGrantDataStream } = await TestDataGenerator.generateGrantCreate({
658
- author: alice,
659
- grantedTo: bob,
660
- scope: {
661
- interface: DwnInterfaceName.Messages,
662
- method: DwnMethodName.Read,
663
- protocol: PermissionsProtocol.uri,
664
- },
665
- });
666
- expect((await dwn.processMessage(alice.did, permissionsGrantMessage, { dataStream: permissionsGrantDataStream })).status.code).toBe(202);
667
- const { message: keyDeliveryGrantMessage, dataStream: keyDeliveryGrantDataStream } = await TestDataGenerator.generateGrantCreate({
668
- author: alice,
669
- grantedTo: bob,
670
- scope: {
671
- interface: DwnInterfaceName.Messages,
672
- method: DwnMethodName.Read,
673
- protocol: KEY_DELIVERY_PROTOCOL_URI,
674
- },
675
- });
676
- expect((await dwn.processMessage(alice.did, keyDeliveryGrantMessage, { dataStream: keyDeliveryGrantDataStream })).status.code).toBe(202);
677
- const { message: carolGrantMessage, dataStream: carolGrantDataStream } = await TestDataGenerator.generateGrantCreate({
678
- author: alice,
679
- grantedTo: carol,
680
- scope: {
681
- interface: DwnInterfaceName.Messages,
682
- method: DwnMethodName.Read,
683
- protocol: 'http://private-delegate-protocol',
684
- },
685
- });
686
- expect((await dwn.processMessage(alice.did, carolGrantMessage, { dataStream: carolGrantDataStream })).status.code).toBe(202);
687
- const { message: readMessage } = await TestDataGenerator.generateMessagesRead({
688
- author: bob,
689
- messageCid: await Message.getCid(carolGrantMessage),
690
- permissionGrantIds: [permissionsGrantMessage.recordId],
691
- });
692
- const readReply = await dwn.processMessage(alice.did, readMessage);
693
- expect(readReply.status.code).toBe(401);
694
- expect(readReply.status.detail).toContain(DwnErrorCode.MessagesReadVerifyScopeFailed);
695
- const stateIndexSyncActions = [
696
- { action: 'root' },
697
- { action: 'subtree', prefix: '' },
698
- { action: 'leaves', prefix: '' },
699
- { action: 'diff', hashes: {}, depth: 2 },
700
- ];
701
- const infrastructureProtocolGrants = [
702
- { protocol: PermissionsProtocol.uri, grantId: permissionsGrantMessage.recordId },
703
- { protocol: KEY_DELIVERY_PROTOCOL_URI, grantId: keyDeliveryGrantMessage.recordId },
704
- ];
705
- for (const { protocol, grantId } of infrastructureProtocolGrants) {
706
- for (const syncAction of stateIndexSyncActions) {
707
- const { message: syncMessage } = await MessagesSync.create({
708
- signer: Jws.createSigner(bob),
709
- ...syncAction,
710
- protocol,
711
- permissionGrantIds: [grantId],
712
- });
713
- const syncReply = await dwn.processMessage(alice.did, syncMessage);
714
- expect(syncReply.status.code).toBe(401);
715
- expect(syncReply.status.detail).toContain(DwnErrorCode.MessagesGrantAuthorizationProtocolSyncInfrastructureProtocol);
716
- }
717
- }
718
- });
719
- it('returns only protocol-scoped diff entries for a delegated protocol grant', async () => {
720
- const alice = await TestDataGenerator.generateDidKeyPersona();
721
- const bob = await TestDataGenerator.generateDidKeyPersona();
722
- const protocolA = { ...freeForAll, protocol: 'http://delegated-diff-protocol-a' };
723
- const protocolB = { ...freeForAll, protocol: 'http://delegated-diff-protocol-b' };
724
- for (const protocolDefinition of [protocolA, protocolB]) {
725
- const { message: protocolMessage } = await TestDataGenerator.generateProtocolsConfigure({
726
- author: alice,
727
- protocolDefinition,
728
- });
729
- expect((await dwn.processMessage(alice.did, protocolMessage)).status.code).toBe(202);
730
- }
731
- const { message: recordA, dataStream: dataStreamA } = await TestDataGenerator.generateRecordsWrite({
732
- author: alice,
733
- protocol: protocolA.protocol,
734
- protocolPath: 'post',
735
- schema: protocolA.types.post.schema,
736
- });
737
- expect((await dwn.processMessage(alice.did, recordA, { dataStream: dataStreamA })).status.code).toBe(202);
738
- const { message: recordB, dataStream: dataStreamB } = await TestDataGenerator.generateRecordsWrite({
739
- author: alice,
740
- protocol: protocolB.protocol,
741
- protocolPath: 'post',
742
- schema: protocolB.types.post.schema,
743
- });
744
- expect((await dwn.processMessage(alice.did, recordB, { dataStream: dataStreamB })).status.code).toBe(202);
745
- const { message: grantMessage, dataStream: grantDataStream } = await TestDataGenerator.generateGrantCreate({
746
- author: alice,
747
- grantedTo: bob,
748
- scope: {
749
- interface: DwnInterfaceName.Messages,
750
- method: DwnMethodName.Read,
751
- protocol: protocolA.protocol,
752
- },
753
- });
754
- expect((await dwn.processMessage(alice.did, grantMessage, { dataStream: grantDataStream })).status.code).toBe(202);
755
- const { message: diffMsg } = await MessagesSync.create({
756
- signer: Jws.createSigner(bob),
757
- action: 'diff',
758
- hashes: {},
759
- depth: 2,
760
- protocol: protocolA.protocol,
761
- permissionGrantIds: [grantMessage.recordId],
762
- });
763
- const reply = await dwn.processMessage(alice.did, diffMsg);
764
- expect(reply.status.code).toBe(200);
765
- const remoteCids = reply.onlyRemote.map(entry => entry.messageCid);
766
- expect(remoteCids).toContain(await Message.getCid(recordA));
767
- expect(remoteCids).not.toContain(await Message.getCid(recordB));
768
- expect(reply.onlyRemote.every(entry => {
769
- if (entry.message?.descriptor.interface !== DwnInterfaceName.Records) {
770
- return true;
771
- }
772
- const recordsMessage = entry.message;
773
- return recordsMessage.descriptor.protocol === protocolA.protocol;
774
- })).toBe(true);
775
- });
776
- });
777
- });
778
- describe('input validation', () => {
779
- it('returns 400 for an unknown action', async () => {
780
- const alice = await TestDataGenerator.generateDidKeyPersona();
781
- const { message } = await MessagesSync.create({
782
- signer: Jws.createSigner(alice),
783
- action: 'root',
784
- });
785
- // manually override to an invalid action
786
- message.descriptor.action = 'invalid';
787
- const handler = new MessagesSyncHandler({ didResolver, messageStore, stateIndex });
788
- const reply = await handler.handle({ tenant: alice.did, message });
789
- expect(reply.status.code).toBe(400);
790
- // the JSON schema validator catches the invalid action before the handler switch/case
791
- expect(reply.status.detail).toContain('SchemaValidatorFailure');
792
- });
793
- it('returns 400 for unknown action that bypasses schema validation (default case)', async () => {
794
- const alice = await TestDataGenerator.generateDidKeyPersona();
795
- const { message } = await MessagesSync.create({
796
- signer: Jws.createSigner(alice),
797
- action: 'root',
798
- });
799
- // Stub MessagesSync.parse to skip schema validation
800
- const parseStub = sinon.stub(MessagesSync, 'parse').resolves({
801
- author: alice.did,
802
- message: message,
803
- signaturePayload: { descriptorCid: 'test' },
804
- });
805
- try {
806
- // Override action to something that passes the stub but hits the default case
807
- message.descriptor.action = 'bogusAction';
808
- const handler = new MessagesSyncHandler({ didResolver, messageStore, stateIndex });
809
- const reply = await handler.handle({ tenant: alice.did, message });
810
- expect(reply.status.code).toBe(400);
811
- expect(reply.status.detail).toContain('Unknown action');
812
- }
813
- finally {
814
- parseStub.restore();
815
- }
816
- });
817
- it('returns 500 for invalid prefix with non-binary characters (via stubbed parse)', async () => {
818
- const alice = await TestDataGenerator.generateDidKeyPersona();
819
- const { message } = await MessagesSync.create({
820
- signer: Jws.createSigner(alice),
821
- action: 'subtree',
822
- prefix: '0',
823
- });
824
- // Stub parse to skip schema validation
825
- const parseStub = sinon.stub(MessagesSync, 'parse').resolves({
826
- author: alice.did,
827
- message: message,
828
- signaturePayload: { descriptorCid: 'test' },
829
- });
830
- try {
831
- // Override prefix to contain invalid characters
832
- message.descriptor.prefix = 'abc';
833
- const handler = new MessagesSyncHandler({ didResolver, messageStore, stateIndex });
834
- const reply = await handler.handle({ tenant: alice.did, message });
835
- expect(reply.status.code).toBe(500);
836
- expect(reply.status.detail).toContain('MessagesSyncInvalidPrefix');
837
- }
838
- finally {
839
- parseStub.restore();
840
- }
841
- });
842
- it('returns 500 for prefix exceeding 256 characters (via stubbed parse)', async () => {
843
- const alice = await TestDataGenerator.generateDidKeyPersona();
844
- const { message } = await MessagesSync.create({
845
- signer: Jws.createSigner(alice),
846
- action: 'subtree',
847
- prefix: '0',
848
- });
849
- // Stub parse to skip schema validation
850
- const parseStub = sinon.stub(MessagesSync, 'parse').resolves({
851
- author: alice.did,
852
- message: message,
853
- signaturePayload: { descriptorCid: 'test' },
854
- });
855
- try {
856
- // Override prefix to be too long
857
- message.descriptor.prefix = '0'.repeat(257);
858
- const handler = new MessagesSyncHandler({ didResolver, messageStore, stateIndex });
859
- const reply = await handler.handle({ tenant: alice.did, message });
860
- expect(reply.status.code).toBe(500);
861
- expect(reply.status.detail).toContain('MessagesSyncInvalidPrefix');
862
- }
863
- finally {
864
- parseStub.restore();
865
- }
866
- });
867
- });
868
- describe('diff action', () => {
869
- it('returns empty diff when client hashes match server hashes', async () => {
870
- const alice = await TestDataGenerator.generateDidKeyPersona();
871
- await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
872
- // write a record
873
- const { message: recordMessage, dataStream } = await TestDataGenerator.generateRecordsWrite({ author: alice });
874
- const writeReply = await dwn.processMessage(alice.did, recordMessage, { dataStream });
875
- expect(writeReply.status.code).toBe(202);
876
- // get the server's subtree hashes at depth 2 via individual subtree requests
877
- const serverHashes = {};
878
- for (const prefix of ['00', '01', '10', '11']) {
879
- const { message: subtreeMsg } = await MessagesSync.create({
880
- signer: Jws.createSigner(alice),
881
- action: 'subtree',
882
- prefix,
883
- });
884
- const subtreeReply = await dwn.processMessage(alice.did, subtreeMsg);
885
- if (subtreeReply.hash) {
886
- serverHashes[prefix] = subtreeReply.hash;
887
- }
888
- }
889
- // send diff with matching hashes — should get empty diff
890
- const { message: diffMsg } = await MessagesSync.create({
891
- signer: Jws.createSigner(alice),
892
- action: 'diff',
893
- hashes: serverHashes,
894
- depth: 2,
895
- });
896
- const reply = await dwn.processMessage(alice.did, diffMsg);
897
- expect(reply.status.code).toBe(200);
898
- expect(reply.onlyRemote).toEqual([]);
899
- expect(reply.onlyLocal).toEqual([]);
900
- });
901
- it('returns onlyRemote entries when client sends empty hashes', async () => {
902
- const alice = await TestDataGenerator.generateDidKeyPersona();
903
- await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
904
- // write a record
905
- const { message: recordMessage, dataStream } = await TestDataGenerator.generateRecordsWrite({ author: alice });
906
- const writeReply = await dwn.processMessage(alice.did, recordMessage, { dataStream });
907
- expect(writeReply.status.code).toBe(202);
908
- // send diff with empty hashes — everything on the server is onlyRemote
909
- const { message: diffMsg } = await MessagesSync.create({
910
- signer: Jws.createSigner(alice),
911
- action: 'diff',
912
- hashes: {},
913
- depth: 2,
914
- });
915
- const reply = await dwn.processMessage(alice.did, diffMsg);
916
- expect(reply.status.code).toBe(200);
917
- expect(reply.onlyRemote.length).toBeGreaterThan(0);
918
- // each entry should have a messageCid and message
919
- for (const entry of reply.onlyRemote) {
920
- expect(typeof entry.messageCid).toBe('string');
921
- expect(entry.message).toBeDefined();
922
- }
923
- });
924
- it('returns onlyLocal prefixes when server has empty subtrees', async () => {
925
- const alice = await TestDataGenerator.generateDidKeyPersona();
926
- // send diff with non-empty client hashes against an empty server
927
- const { message: diffMsg } = await MessagesSync.create({
928
- signer: Jws.createSigner(alice),
929
- action: 'diff',
930
- hashes: { '00': 'aabbccdd', '01': '11223344' },
931
- depth: 2,
932
- });
933
- const reply = await dwn.processMessage(alice.did, diffMsg);
934
- expect(reply.status.code).toBe(200);
935
- expect(reply.onlyRemote).toEqual([]);
936
- expect(reply.onlyLocal).toContain('00');
937
- expect(reply.onlyLocal).toContain('01');
938
- });
939
- it('prunes empty server subtrees at the current diff depth', async () => {
940
- const alice = await TestDataGenerator.generateDidKeyPersona();
941
- const getSubtreeHashSpy = sinon.spy(stateIndex, 'getSubtreeHash');
942
- try {
943
- const { message: diffMsg } = await MessagesSync.create({
944
- signer: Jws.createSigner(alice),
945
- action: 'diff',
946
- hashes: {},
947
- depth: 64,
948
- });
949
- const reply = await dwn.processMessage(alice.did, diffMsg);
950
- expect(reply.status.code).toBe(200);
951
- expect(reply.onlyRemote).toEqual([]);
952
- expect(reply.onlyLocal).toEqual([]);
953
- expect(getSubtreeHashSpy.callCount).toBe(1);
954
- }
955
- finally {
956
- getSubtreeHashSpy.restore();
957
- }
958
- });
959
- it('inlines small data payloads as encodedData in onlyRemote entries', async () => {
960
- const alice = await TestDataGenerator.generateDidKeyPersona();
961
- await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
962
- // write a small record
963
- const { message: recordMessage, dataStream } = await TestDataGenerator.generateRecordsWrite({
964
- author: alice,
965
- data: new TextEncoder().encode('small payload'),
966
- dataFormat: 'text/plain',
967
- });
968
- const writeReply = await dwn.processMessage(alice.did, recordMessage, { dataStream });
969
- expect(writeReply.status.code).toBe(202);
970
- // diff with empty client — server should inline the data
971
- const { message: diffMsg } = await MessagesSync.create({
972
- signer: Jws.createSigner(alice),
973
- action: 'diff',
974
- hashes: {},
975
- depth: 2,
976
- });
977
- const reply = await dwn.processMessage(alice.did, diffMsg);
978
- expect(reply.status.code).toBe(200);
979
- // find the RecordsWrite entry
980
- const recordEntry = reply.onlyRemote.find((e) => e.message?.descriptor.interface === 'Records' && e.message?.descriptor.method === 'Write');
981
- expect(recordEntry).toBeDefined();
982
- expect(recordEntry.encodedData).toBeDefined();
983
- expect(typeof recordEntry.encodedData).toBe('string');
984
- });
985
- it('inlines small dataStore-backed payloads using the RecordsWrite recordId', async () => {
986
- const alice = await TestDataGenerator.generateDidKeyPersona();
987
- await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
988
- const dataBytes = new TextEncoder().encode('small data-store payload');
989
- const { message: recordMessage, recordsWrite } = await TestDataGenerator.generateRecordsWrite({
990
- author: alice,
991
- data: dataBytes,
992
- dataFormat: 'text/plain',
993
- });
994
- const indexes = await recordsWrite.constructIndexes(true);
995
- const messageCid = await Message.getCid(recordMessage);
996
- await dataStore.put(alice.did, recordMessage.recordId, recordMessage.descriptor.dataCid, DataStream.fromBytes(dataBytes));
997
- await messageStore.put(alice.did, recordMessage, indexes);
998
- await stateIndex.insert(alice.did, messageCid, indexes);
999
- const { message: diffMsg } = await MessagesSync.create({
1000
- signer: Jws.createSigner(alice),
1001
- action: 'diff',
1002
- hashes: {},
1003
- depth: 2,
1004
- });
1005
- const reply = await dwn.processMessage(alice.did, diffMsg);
1006
- expect(reply.status.code).toBe(200);
1007
- const recordEntry = reply.onlyRemote.find(entry => entry.messageCid === messageCid);
1008
- expect(recordEntry).toBeDefined();
1009
- expect(recordEntry.encodedData).toBe(Encoder.bytesToBase64Url(dataBytes));
1010
- });
1011
- it('returns 400 when hashes or depth are missing', async () => {
1012
- const alice = await TestDataGenerator.generateDidKeyPersona();
1013
- // create a valid diff message then strip required fields
1014
- const { message } = await MessagesSync.create({
1015
- signer: Jws.createSigner(alice),
1016
- action: 'diff',
1017
- hashes: {},
1018
- depth: 2,
1019
- });
1020
- // stub parse to skip schema validation
1021
- const parseStub = sinon.stub(MessagesSync, 'parse').resolves({
1022
- author: alice.did,
1023
- message,
1024
- signaturePayload: { descriptorCid: 'test' },
1025
- });
1026
- try {
1027
- // remove hashes to trigger the guard
1028
- delete message.descriptor.hashes;
1029
- const handler = new MessagesSyncHandler({ didResolver, messageStore, stateIndex, dataStore });
1030
- const reply = await handler.handle({ tenant: alice.did, message });
1031
- expect(reply.status.code).toBe(400);
1032
- expect(reply.status.detail).toContain('diff action requires hashes and depth');
1033
- }
1034
- finally {
1035
- parseStub.restore();
1036
- }
1037
- });
1038
- it('handles protocol-scoped diff', async () => {
1039
- const alice = await TestDataGenerator.generateDidKeyPersona();
1040
- await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
1041
- // write a record using the default test protocol
1042
- const { message: recordMessage, dataStream } = await TestDataGenerator.generateRecordsWrite({
1043
- author: alice,
1044
- });
1045
- const writeReply = await dwn.processMessage(alice.did, recordMessage, { dataStream });
1046
- expect(writeReply.status.code).toBe(202);
1047
- // diff scoped to the default test protocol
1048
- const protocol = recordMessage.descriptor.protocol;
1049
- const { message: diffMsg } = await MessagesSync.create({
1050
- signer: Jws.createSigner(alice),
1051
- action: 'diff',
1052
- hashes: {},
1053
- depth: 2,
1054
- protocol,
1055
- });
1056
- const reply = await dwn.processMessage(alice.did, diffMsg);
1057
- expect(reply.status.code).toBe(200);
1058
- expect(reply.onlyRemote.length).toBeGreaterThan(0);
1059
- });
1060
- });
1061
- describe('error handling', () => {
1062
- it('returns 500 when stateIndex throws an unexpected error', async () => {
1063
- const alice = await TestDataGenerator.generateDidKeyPersona();
1064
- const failingStateIndex = {
1065
- open: async () => { },
1066
- close: async () => { },
1067
- clear: async () => { },
1068
- insert: async () => { },
1069
- delete: async () => { },
1070
- getRoot: async () => { throw new Error('Unexpected DB failure'); },
1071
- getProtocolRoot: async () => { throw new Error('Unexpected DB failure'); },
1072
- getSubtreeHash: async () => { throw new Error('Unexpected DB failure'); },
1073
- getProtocolSubtreeHash: async () => { throw new Error('Unexpected DB failure'); },
1074
- getLeaves: async () => { throw new Error('Unexpected DB failure'); },
1075
- getProtocolLeaves: async () => { throw new Error('Unexpected DB failure'); },
1076
- };
1077
- const handler = new MessagesSyncHandler({ didResolver, messageStore, stateIndex: failingStateIndex });
1078
- const { message } = await MessagesSync.create({
1079
- signer: Jws.createSigner(alice),
1080
- action: 'root',
1081
- });
1082
- const reply = await handler.handle({ tenant: alice.did, message });
1083
- expect(reply.status.code).toBe(500);
1084
- });
1085
- });
1086
- });
1087
- }
1088
- //# sourceMappingURL=messages-sync.spec.js.map