@enbox/dwn-sdk-js 0.0.7 → 0.1.0

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 (368) hide show
  1. package/dist/browser.mjs +8 -8
  2. package/dist/browser.mjs.map +4 -4
  3. package/dist/esm/generated/precompiled-validators.js +817 -911
  4. package/dist/esm/generated/precompiled-validators.js.map +1 -1
  5. package/dist/esm/src/core/constants.js +11 -0
  6. package/dist/esm/src/core/constants.js.map +1 -0
  7. package/dist/esm/src/core/core-protocol.js +44 -0
  8. package/dist/esm/src/core/core-protocol.js.map +1 -0
  9. package/dist/esm/src/core/dwn-error.js +12 -12
  10. package/dist/esm/src/core/dwn-error.js.map +1 -1
  11. package/dist/esm/src/core/grant-authorization.js +16 -3
  12. package/dist/esm/src/core/grant-authorization.js.map +1 -1
  13. package/dist/esm/src/core/protocol-authorization-action.js +5 -0
  14. package/dist/esm/src/core/protocol-authorization-action.js.map +1 -1
  15. package/dist/esm/src/core/protocol-authorization-validation.js +91 -0
  16. package/dist/esm/src/core/protocol-authorization-validation.js.map +1 -1
  17. package/dist/esm/src/core/protocol-authorization.js +53 -30
  18. package/dist/esm/src/core/protocol-authorization.js.map +1 -1
  19. package/dist/esm/src/core/records-grant-authorization.js +6 -8
  20. package/dist/esm/src/core/records-grant-authorization.js.map +1 -1
  21. package/dist/esm/src/core/resumable-task-manager.js +2 -0
  22. package/dist/esm/src/core/resumable-task-manager.js.map +1 -1
  23. package/dist/esm/src/dwn.js +42 -18
  24. package/dist/esm/src/dwn.js.map +1 -1
  25. package/dist/esm/src/event-stream/event-emitter-event-log.js +204 -0
  26. package/dist/esm/src/event-stream/event-emitter-event-log.js.map +1 -0
  27. package/dist/esm/src/handlers/messages-read.js +7 -11
  28. package/dist/esm/src/handlers/messages-read.js.map +1 -1
  29. package/dist/esm/src/handlers/messages-subscribe.js +22 -24
  30. package/dist/esm/src/handlers/messages-subscribe.js.map +1 -1
  31. package/dist/esm/src/handlers/messages-sync.js +11 -15
  32. package/dist/esm/src/handlers/messages-sync.js.map +1 -1
  33. package/dist/esm/src/handlers/protocols-configure.js +37 -27
  34. package/dist/esm/src/handlers/protocols-configure.js.map +1 -1
  35. package/dist/esm/src/handlers/protocols-query.js +7 -11
  36. package/dist/esm/src/handlers/protocols-query.js.map +1 -1
  37. package/dist/esm/src/handlers/records-count.js +10 -12
  38. package/dist/esm/src/handlers/records-count.js.map +1 -1
  39. package/dist/esm/src/handlers/records-delete.js +10 -18
  40. package/dist/esm/src/handlers/records-delete.js.map +1 -1
  41. package/dist/esm/src/handlers/records-query.js +11 -15
  42. package/dist/esm/src/handlers/records-query.js.map +1 -1
  43. package/dist/esm/src/handlers/records-read.js +31 -26
  44. package/dist/esm/src/handlers/records-read.js.map +1 -1
  45. package/dist/esm/src/handlers/records-subscribe.js +39 -26
  46. package/dist/esm/src/handlers/records-subscribe.js.map +1 -1
  47. package/dist/esm/src/handlers/records-write.js +128 -105
  48. package/dist/esm/src/handlers/records-write.js.map +1 -1
  49. package/dist/esm/src/index.js +5 -2
  50. package/dist/esm/src/index.js.map +1 -1
  51. package/dist/esm/src/interfaces/messages-subscribe.js +1 -0
  52. package/dist/esm/src/interfaces/messages-subscribe.js.map +1 -1
  53. package/dist/esm/src/interfaces/protocols-configure.js +33 -3
  54. package/dist/esm/src/interfaces/protocols-configure.js.map +1 -1
  55. package/dist/esm/src/interfaces/records-count.js +1 -1
  56. package/dist/esm/src/interfaces/records-count.js.map +1 -1
  57. package/dist/esm/src/interfaces/records-delete.js +1 -1
  58. package/dist/esm/src/interfaces/records-delete.js.map +1 -1
  59. package/dist/esm/src/interfaces/records-query.js +1 -1
  60. package/dist/esm/src/interfaces/records-query.js.map +1 -1
  61. package/dist/esm/src/interfaces/records-read.js +1 -1
  62. package/dist/esm/src/interfaces/records-read.js.map +1 -1
  63. package/dist/esm/src/interfaces/records-subscribe.js +2 -1
  64. package/dist/esm/src/interfaces/records-subscribe.js.map +1 -1
  65. package/dist/esm/src/interfaces/records-write-signing.js +1 -12
  66. package/dist/esm/src/interfaces/records-write-signing.js.map +1 -1
  67. package/dist/esm/src/interfaces/records-write.js +25 -41
  68. package/dist/esm/src/interfaces/records-write.js.map +1 -1
  69. package/dist/esm/src/protocols/permission-grant.js +1 -1
  70. package/dist/esm/src/protocols/permission-grant.js.map +1 -1
  71. package/dist/esm/src/protocols/permission-request.js +1 -1
  72. package/dist/esm/src/protocols/permission-request.js.map +1 -1
  73. package/dist/esm/src/protocols/permissions.js +113 -5
  74. package/dist/esm/src/protocols/permissions.js.map +1 -1
  75. package/dist/esm/src/state-index/state-index-level.js +5 -7
  76. package/dist/esm/src/state-index/state-index-level.js.map +1 -1
  77. package/dist/esm/src/store/data-store-level.js +110 -33
  78. package/dist/esm/src/store/data-store-level.js.map +1 -1
  79. package/dist/esm/src/store/index-level.js +42 -32
  80. package/dist/esm/src/store/index-level.js.map +1 -1
  81. package/dist/esm/src/store/storage-controller.js +70 -6
  82. package/dist/esm/src/store/storage-controller.js.map +1 -1
  83. package/dist/esm/src/types/permission-types.js.map +1 -1
  84. package/dist/esm/src/types/protocols-types.js +11 -0
  85. package/dist/esm/src/types/protocols-types.js.map +1 -1
  86. package/dist/esm/src/types/records-types.js.map +1 -1
  87. package/dist/esm/src/utils/hd-key.js +0 -8
  88. package/dist/esm/src/utils/hd-key.js.map +1 -1
  89. package/dist/esm/src/utils/messages.js +16 -34
  90. package/dist/esm/src/utils/messages.js.map +1 -1
  91. package/dist/esm/src/utils/records.js +5 -43
  92. package/dist/esm/src/utils/records.js.map +1 -1
  93. package/dist/esm/tests/core/protocol-authorization.spec.js +2 -1
  94. package/dist/esm/tests/core/protocol-authorization.spec.js.map +1 -1
  95. package/dist/esm/tests/dwn.spec.js +32 -43
  96. package/dist/esm/tests/dwn.spec.js.map +1 -1
  97. package/dist/esm/tests/event-emitter-event-log.spec.js +305 -0
  98. package/dist/esm/tests/event-emitter-event-log.spec.js.map +1 -0
  99. package/dist/esm/tests/features/author-delegated-grant.spec.js +14 -7
  100. package/dist/esm/tests/features/author-delegated-grant.spec.js.map +1 -1
  101. package/dist/esm/tests/features/owner-delegated-grant.spec.js +9 -5
  102. package/dist/esm/tests/features/owner-delegated-grant.spec.js.map +1 -1
  103. package/dist/esm/tests/features/owner-signature.spec.js +14 -7
  104. package/dist/esm/tests/features/owner-signature.spec.js.map +1 -1
  105. package/dist/esm/tests/features/permissions.spec.js +12 -12
  106. package/dist/esm/tests/features/permissions.spec.js.map +1 -1
  107. package/dist/esm/tests/features/protocol-composition.spec.js +636 -5
  108. package/dist/esm/tests/features/protocol-composition.spec.js.map +1 -1
  109. package/dist/esm/tests/features/protocol-create-action.spec.js +4 -4
  110. package/dist/esm/tests/features/protocol-create-action.spec.js.map +1 -1
  111. package/dist/esm/tests/features/protocol-delete-action.spec.js +7 -7
  112. package/dist/esm/tests/features/protocol-delete-action.spec.js.map +1 -1
  113. package/dist/esm/tests/features/protocol-update-action.spec.js +4 -4
  114. package/dist/esm/tests/features/protocol-update-action.spec.js.map +1 -1
  115. package/dist/esm/tests/features/records-delivery.spec.js +236 -0
  116. package/dist/esm/tests/features/records-delivery.spec.js.map +1 -0
  117. package/dist/esm/tests/features/records-immutable.spec.js +315 -0
  118. package/dist/esm/tests/features/records-immutable.spec.js.map +1 -0
  119. package/dist/esm/tests/features/records-prune.spec.js +4 -4
  120. package/dist/esm/tests/features/records-prune.spec.js.map +1 -1
  121. package/dist/esm/tests/features/records-record-limit.spec.js +542 -0
  122. package/dist/esm/tests/features/records-record-limit.spec.js.map +1 -0
  123. package/dist/esm/tests/features/records-squash.spec.js +1055 -0
  124. package/dist/esm/tests/features/records-squash.spec.js.map +1 -0
  125. package/dist/esm/tests/features/records-tags.spec.js +16 -4
  126. package/dist/esm/tests/features/records-tags.spec.js.map +1 -1
  127. package/dist/esm/tests/features/resumable-tasks.spec.js +7 -8
  128. package/dist/esm/tests/features/resumable-tasks.spec.js.map +1 -1
  129. package/dist/esm/tests/handlers/messages-read.spec.js +11 -5
  130. package/dist/esm/tests/handlers/messages-read.spec.js.map +1 -1
  131. package/dist/esm/tests/handlers/messages-subscribe.spec.js +169 -22
  132. package/dist/esm/tests/handlers/messages-subscribe.spec.js.map +1 -1
  133. package/dist/esm/tests/handlers/messages-sync.spec.js +103 -21
  134. package/dist/esm/tests/handlers/messages-sync.spec.js.map +1 -1
  135. package/dist/esm/tests/handlers/protocols-configure.spec.js +5 -5
  136. package/dist/esm/tests/handlers/protocols-configure.spec.js.map +1 -1
  137. package/dist/esm/tests/handlers/protocols-query.spec.js +5 -5
  138. package/dist/esm/tests/handlers/protocols-query.spec.js.map +1 -1
  139. package/dist/esm/tests/handlers/records-count.spec.js +9 -4
  140. package/dist/esm/tests/handlers/records-count.spec.js.map +1 -1
  141. package/dist/esm/tests/handlers/records-delete.spec.js +24 -25
  142. package/dist/esm/tests/handlers/records-delete.spec.js.map +1 -1
  143. package/dist/esm/tests/handlers/records-query.spec.js +68 -9
  144. package/dist/esm/tests/handlers/records-query.spec.js.map +1 -1
  145. package/dist/esm/tests/handlers/records-read.spec.js +24 -138
  146. package/dist/esm/tests/handlers/records-read.spec.js.map +1 -1
  147. package/dist/esm/tests/handlers/records-subscribe.spec.js +175 -35
  148. package/dist/esm/tests/handlers/records-subscribe.spec.js.map +1 -1
  149. package/dist/esm/tests/handlers/records-write.spec.js +176 -72
  150. package/dist/esm/tests/handlers/records-write.spec.js.map +1 -1
  151. package/dist/esm/tests/interfaces/records-write.spec.js +52 -68
  152. package/dist/esm/tests/interfaces/records-write.spec.js.map +1 -1
  153. package/dist/esm/tests/protocols/permission-grant.spec.js +6 -6
  154. package/dist/esm/tests/protocols/permission-grant.spec.js.map +1 -1
  155. package/dist/esm/tests/protocols/permission-request.spec.js +4 -4
  156. package/dist/esm/tests/protocols/permission-request.spec.js.map +1 -1
  157. package/dist/esm/tests/protocols/permissions.spec.js +4 -4
  158. package/dist/esm/tests/protocols/permissions.spec.js.map +1 -1
  159. package/dist/esm/tests/scenarios/aggregator.spec.js +4 -4
  160. package/dist/esm/tests/scenarios/aggregator.spec.js.map +1 -1
  161. package/dist/esm/tests/scenarios/deleted-record.spec.js +350 -5
  162. package/dist/esm/tests/scenarios/deleted-record.spec.js.map +1 -1
  163. package/dist/esm/tests/scenarios/end-to-end-tests.spec.js +4 -4
  164. package/dist/esm/tests/scenarios/end-to-end-tests.spec.js.map +1 -1
  165. package/dist/esm/tests/scenarios/nested-roles.spec.js +4 -4
  166. package/dist/esm/tests/scenarios/nested-roles.spec.js.map +1 -1
  167. package/dist/esm/tests/scenarios/subscriptions.spec.js +93 -40
  168. package/dist/esm/tests/scenarios/subscriptions.spec.js.map +1 -1
  169. package/dist/esm/tests/store/data-store-level.spec.js +102 -41
  170. package/dist/esm/tests/store/data-store-level.spec.js.map +1 -1
  171. package/dist/esm/tests/test-event-stream.js +12 -13
  172. package/dist/esm/tests/test-event-stream.js.map +1 -1
  173. package/dist/esm/tests/test-suite.js +10 -4
  174. package/dist/esm/tests/test-suite.js.map +1 -1
  175. package/dist/esm/tests/utils/messages.spec.js +12 -5
  176. package/dist/esm/tests/utils/messages.spec.js.map +1 -1
  177. package/dist/esm/tests/utils/records.spec.js +8 -12
  178. package/dist/esm/tests/utils/records.spec.js.map +1 -1
  179. package/dist/esm/tests/utils/test-data-generator.js +36 -2
  180. package/dist/esm/tests/utils/test-data-generator.js.map +1 -1
  181. package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js +37 -8
  182. package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js.map +1 -1
  183. package/dist/types/generated/precompiled-validators.d.ts +49 -40
  184. package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
  185. package/dist/types/src/core/constants.d.ts +11 -0
  186. package/dist/types/src/core/constants.d.ts.map +1 -0
  187. package/dist/types/src/core/core-protocol.d.ts +89 -0
  188. package/dist/types/src/core/core-protocol.d.ts.map +1 -0
  189. package/dist/types/src/core/dwn-error.d.ts +12 -12
  190. package/dist/types/src/core/dwn-error.d.ts.map +1 -1
  191. package/dist/types/src/core/grant-authorization.d.ts +6 -2
  192. package/dist/types/src/core/grant-authorization.d.ts.map +1 -1
  193. package/dist/types/src/core/protocol-authorization-action.d.ts.map +1 -1
  194. package/dist/types/src/core/protocol-authorization-validation.d.ts +30 -0
  195. package/dist/types/src/core/protocol-authorization-validation.d.ts.map +1 -1
  196. package/dist/types/src/core/protocol-authorization.d.ts +19 -11
  197. package/dist/types/src/core/protocol-authorization.d.ts.map +1 -1
  198. package/dist/types/src/core/records-grant-authorization.d.ts.map +1 -1
  199. package/dist/types/src/core/resumable-task-manager.d.ts +2 -1
  200. package/dist/types/src/core/resumable-task-manager.d.ts.map +1 -1
  201. package/dist/types/src/dwn.d.ts +19 -7
  202. package/dist/types/src/dwn.d.ts.map +1 -1
  203. package/dist/types/src/event-stream/event-emitter-event-log.d.ts +50 -0
  204. package/dist/types/src/event-stream/event-emitter-event-log.d.ts.map +1 -0
  205. package/dist/types/src/handlers/messages-read.d.ts +3 -8
  206. package/dist/types/src/handlers/messages-read.d.ts.map +1 -1
  207. package/dist/types/src/handlers/messages-subscribe.d.ts +6 -10
  208. package/dist/types/src/handlers/messages-subscribe.d.ts.map +1 -1
  209. package/dist/types/src/handlers/messages-sync.d.ts +3 -8
  210. package/dist/types/src/handlers/messages-sync.d.ts.map +1 -1
  211. package/dist/types/src/handlers/protocols-configure.d.ts +3 -10
  212. package/dist/types/src/handlers/protocols-configure.d.ts.map +1 -1
  213. package/dist/types/src/handlers/protocols-query.d.ts +3 -8
  214. package/dist/types/src/handlers/protocols-query.d.ts.map +1 -1
  215. package/dist/types/src/handlers/records-count.d.ts +3 -6
  216. package/dist/types/src/handlers/records-count.d.ts.map +1 -1
  217. package/dist/types/src/handlers/records-delete.d.ts +3 -8
  218. package/dist/types/src/handlers/records-delete.d.ts.map +1 -1
  219. package/dist/types/src/handlers/records-query.d.ts +3 -8
  220. package/dist/types/src/handlers/records-query.d.ts.map +1 -1
  221. package/dist/types/src/handlers/records-read.d.ts +3 -8
  222. package/dist/types/src/handlers/records-read.d.ts.map +1 -1
  223. package/dist/types/src/handlers/records-subscribe.d.ts +8 -10
  224. package/dist/types/src/handlers/records-subscribe.d.ts.map +1 -1
  225. package/dist/types/src/handlers/records-write.d.ts +12 -25
  226. package/dist/types/src/handlers/records-write.d.ts.map +1 -1
  227. package/dist/types/src/index.d.ts +8 -4
  228. package/dist/types/src/index.d.ts.map +1 -1
  229. package/dist/types/src/interfaces/messages-subscribe.d.ts +5 -0
  230. package/dist/types/src/interfaces/messages-subscribe.d.ts.map +1 -1
  231. package/dist/types/src/interfaces/protocols-configure.d.ts.map +1 -1
  232. package/dist/types/src/interfaces/records-subscribe.d.ts +5 -0
  233. package/dist/types/src/interfaces/records-subscribe.d.ts.map +1 -1
  234. package/dist/types/src/interfaces/records-write-signing.d.ts +3 -4
  235. package/dist/types/src/interfaces/records-write-signing.d.ts.map +1 -1
  236. package/dist/types/src/interfaces/records-write.d.ts +11 -11
  237. package/dist/types/src/interfaces/records-write.d.ts.map +1 -1
  238. package/dist/types/src/protocols/permission-grant.d.ts +1 -1
  239. package/dist/types/src/protocols/permission-grant.d.ts.map +1 -1
  240. package/dist/types/src/protocols/permission-request.d.ts +1 -1
  241. package/dist/types/src/protocols/permission-request.d.ts.map +1 -1
  242. package/dist/types/src/protocols/permissions.d.ts +40 -3
  243. package/dist/types/src/protocols/permissions.d.ts.map +1 -1
  244. package/dist/types/src/state-index/state-index-level.d.ts.map +1 -1
  245. package/dist/types/src/store/data-store-level.d.ts +20 -4
  246. package/dist/types/src/store/data-store-level.d.ts.map +1 -1
  247. package/dist/types/src/store/index-level.d.ts +4 -0
  248. package/dist/types/src/store/index-level.d.ts.map +1 -1
  249. package/dist/types/src/store/storage-controller.d.ts +20 -6
  250. package/dist/types/src/store/storage-controller.d.ts.map +1 -1
  251. package/dist/types/src/types/message-types.d.ts +3 -3
  252. package/dist/types/src/types/message-types.d.ts.map +1 -1
  253. package/dist/types/src/types/messages-types.d.ts +12 -3
  254. package/dist/types/src/types/messages-types.d.ts.map +1 -1
  255. package/dist/types/src/types/method-handler.d.ts +24 -3
  256. package/dist/types/src/types/method-handler.d.ts.map +1 -1
  257. package/dist/types/src/types/permission-types.d.ts +7 -0
  258. package/dist/types/src/types/permission-types.d.ts.map +1 -1
  259. package/dist/types/src/types/protocols-types.d.ts +69 -2
  260. package/dist/types/src/types/protocols-types.d.ts.map +1 -1
  261. package/dist/types/src/types/records-types.d.ts +23 -6
  262. package/dist/types/src/types/records-types.d.ts.map +1 -1
  263. package/dist/types/src/types/subscriptions.d.ts +151 -13
  264. package/dist/types/src/types/subscriptions.d.ts.map +1 -1
  265. package/dist/types/src/utils/hd-key.d.ts +1 -9
  266. package/dist/types/src/utils/hd-key.d.ts.map +1 -1
  267. package/dist/types/src/utils/messages.d.ts +7 -5
  268. package/dist/types/src/utils/messages.d.ts.map +1 -1
  269. package/dist/types/src/utils/records.d.ts +1 -11
  270. package/dist/types/src/utils/records.d.ts.map +1 -1
  271. package/dist/types/tests/dwn.spec.d.ts.map +1 -1
  272. package/dist/types/tests/event-emitter-event-log.spec.d.ts +2 -0
  273. package/dist/types/tests/event-emitter-event-log.spec.d.ts.map +1 -0
  274. package/dist/types/tests/features/author-delegated-grant.spec.d.ts.map +1 -1
  275. package/dist/types/tests/features/owner-delegated-grant.spec.d.ts.map +1 -1
  276. package/dist/types/tests/features/owner-signature.spec.d.ts.map +1 -1
  277. package/dist/types/tests/features/protocol-composition.spec.d.ts.map +1 -1
  278. package/dist/types/tests/features/records-delivery.spec.d.ts +2 -0
  279. package/dist/types/tests/features/records-delivery.spec.d.ts.map +1 -0
  280. package/dist/types/tests/features/records-immutable.spec.d.ts +2 -0
  281. package/dist/types/tests/features/records-immutable.spec.d.ts.map +1 -0
  282. package/dist/types/tests/features/records-record-limit.spec.d.ts +2 -0
  283. package/dist/types/tests/features/records-record-limit.spec.d.ts.map +1 -0
  284. package/dist/types/tests/features/records-squash.spec.d.ts +2 -0
  285. package/dist/types/tests/features/records-squash.spec.d.ts.map +1 -0
  286. package/dist/types/tests/features/records-tags.spec.d.ts.map +1 -1
  287. package/dist/types/tests/features/resumable-tasks.spec.d.ts.map +1 -1
  288. package/dist/types/tests/handlers/messages-read.spec.d.ts.map +1 -1
  289. package/dist/types/tests/handlers/messages-subscribe.spec.d.ts.map +1 -1
  290. package/dist/types/tests/handlers/messages-sync.spec.d.ts.map +1 -1
  291. package/dist/types/tests/handlers/records-count.spec.d.ts.map +1 -1
  292. package/dist/types/tests/handlers/records-delete.spec.d.ts.map +1 -1
  293. package/dist/types/tests/handlers/records-query.spec.d.ts.map +1 -1
  294. package/dist/types/tests/handlers/records-read.spec.d.ts.map +1 -1
  295. package/dist/types/tests/handlers/records-subscribe.spec.d.ts.map +1 -1
  296. package/dist/types/tests/handlers/records-write.spec.d.ts.map +1 -1
  297. package/dist/types/tests/scenarios/deleted-record.spec.d.ts.map +1 -1
  298. package/dist/types/tests/scenarios/subscriptions.spec.d.ts.map +1 -1
  299. package/dist/types/tests/test-event-stream.d.ts +11 -12
  300. package/dist/types/tests/test-event-stream.d.ts.map +1 -1
  301. package/dist/types/tests/test-suite.d.ts +2 -2
  302. package/dist/types/tests/test-suite.d.ts.map +1 -1
  303. package/dist/types/tests/utils/test-data-generator.d.ts +19 -0
  304. package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -1
  305. package/package.json +5 -4
  306. package/src/core/constants.ts +11 -0
  307. package/src/core/core-protocol.ts +129 -0
  308. package/src/core/dwn-error.ts +18 -12
  309. package/src/core/grant-authorization.ts +20 -3
  310. package/src/core/protocol-authorization-action.ts +5 -0
  311. package/src/core/protocol-authorization-validation.ts +133 -0
  312. package/src/core/protocol-authorization.ts +71 -23
  313. package/src/core/records-grant-authorization.ts +6 -8
  314. package/src/core/resumable-task-manager.ts +3 -1
  315. package/src/dwn.ts +58 -73
  316. package/src/event-stream/event-emitter-event-log.ts +283 -0
  317. package/src/handlers/messages-read.ts +8 -9
  318. package/src/handlers/messages-subscribe.ts +24 -28
  319. package/src/handlers/messages-sync.ts +10 -16
  320. package/src/handlers/protocols-configure.ts +47 -32
  321. package/src/handlers/protocols-query.ts +6 -9
  322. package/src/handlers/records-count.ts +11 -10
  323. package/src/handlers/records-delete.ts +12 -21
  324. package/src/handlers/records-query.ts +12 -12
  325. package/src/handlers/records-read.ts +34 -22
  326. package/src/handlers/records-subscribe.ts +47 -26
  327. package/src/handlers/records-write.ts +152 -119
  328. package/src/index.ts +9 -5
  329. package/src/interfaces/messages-subscribe.ts +7 -1
  330. package/src/interfaces/protocols-configure.ts +51 -3
  331. package/src/interfaces/records-count.ts +1 -1
  332. package/src/interfaces/records-delete.ts +1 -1
  333. package/src/interfaces/records-query.ts +1 -1
  334. package/src/interfaces/records-read.ts +1 -1
  335. package/src/interfaces/records-subscribe.ts +8 -1
  336. package/src/interfaces/records-write-signing.ts +2 -22
  337. package/src/interfaces/records-write.ts +35 -48
  338. package/src/protocols/permission-grant.ts +1 -1
  339. package/src/protocols/permission-request.ts +1 -1
  340. package/src/protocols/permissions.ts +148 -6
  341. package/src/state-index/state-index-level.ts +5 -7
  342. package/src/store/data-store-level.ts +124 -34
  343. package/src/store/index-level.ts +44 -35
  344. package/src/store/storage-controller.ts +89 -12
  345. package/src/types/message-types.ts +3 -3
  346. package/src/types/messages-types.ts +12 -3
  347. package/src/types/method-handler.ts +26 -4
  348. package/src/types/mitt.d.ts +28 -0
  349. package/src/types/permission-types.ts +7 -0
  350. package/src/types/protocols-types.ts +78 -1
  351. package/src/types/records-types.ts +24 -6
  352. package/src/types/subscriptions.ts +178 -14
  353. package/src/utils/hd-key.ts +0 -9
  354. package/src/utils/messages.ts +17 -37
  355. package/src/utils/records.ts +7 -58
  356. package/dist/esm/src/event-stream/event-emitter-stream.js +0 -46
  357. package/dist/esm/src/event-stream/event-emitter-stream.js.map +0 -1
  358. package/dist/esm/tests/event-stream/event-emitter-stream.spec.js +0 -68
  359. package/dist/esm/tests/event-stream/event-emitter-stream.spec.js.map +0 -1
  360. package/dist/esm/tests/event-stream/event-stream.spec.js +0 -114
  361. package/dist/esm/tests/event-stream/event-stream.spec.js.map +0 -1
  362. package/dist/types/src/event-stream/event-emitter-stream.d.ts +0 -23
  363. package/dist/types/src/event-stream/event-emitter-stream.d.ts.map +0 -1
  364. package/dist/types/tests/event-stream/event-emitter-stream.spec.d.ts +0 -2
  365. package/dist/types/tests/event-stream/event-emitter-stream.spec.d.ts.map +0 -1
  366. package/dist/types/tests/event-stream/event-stream.spec.d.ts +0 -2
  367. package/dist/types/tests/event-stream/event-stream.spec.d.ts.map +0 -1
  368. package/src/event-stream/event-emitter-stream.ts +0 -69
@@ -1,14 +1,13 @@
1
- import type { DidResolver } from '@enbox/dids';
1
+ import type { CoreProtocolRegistry } from '../core/core-protocol.js';
2
2
  import type { MessageSort } from '../types/message-types.js';
3
3
  import type { MessageStore } from '../types//message-store.js';
4
- import type { MethodHandler } from '../types/method-handler.js';
5
- import type { EventListener, EventStream } from '../types/subscriptions.js';
4
+ import type { SubscriptionListener } from '../types/subscriptions.js';
6
5
  import type { Filter, PaginationCursor } from '../types/query-types.js';
7
- import type { RecordEvent, RecordsQueryReplyEntry, RecordsSubscribeMessage, RecordsSubscribeReply, RecordSubscriptionHandler } from '../types/records-types.js';
6
+ import type { HandlerDependencies, MethodHandler } from '../types/method-handler.js';
7
+ import type { RecordsQueryReplyEntry, RecordsSubscribeMessage, RecordsSubscribeReply } from '../types/records-types.js';
8
8
 
9
9
  import { authenticate } from '../core/auth.js';
10
10
  import { DateSort } from '../types/records-types.js';
11
- import { FilterUtility } from '../utils/filter.js';
12
11
  import { Message } from '../core/message.js';
13
12
  import { messageReplyFromError } from '../core/message-reply.js';
14
13
  import { ProtocolAuthorization } from '../core/protocol-authorization.js';
@@ -21,7 +20,7 @@ import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.j
21
20
 
22
21
  export class RecordsSubscribeHandler implements MethodHandler {
23
22
 
24
- constructor(private didResolver: DidResolver, private messageStore: MessageStore, private eventStream?: EventStream) { }
23
+ constructor(private deps: HandlerDependencies) { }
25
24
 
26
25
  public async handle({
27
26
  tenant,
@@ -30,11 +29,11 @@ export class RecordsSubscribeHandler implements MethodHandler {
30
29
  }: {
31
30
  tenant: string,
32
31
  message: RecordsSubscribeMessage,
33
- subscriptionHandler: RecordSubscriptionHandler,
32
+ subscriptionHandler: SubscriptionListener,
34
33
  }): Promise<RecordsSubscribeReply> {
35
- if (this.eventStream === undefined) {
34
+ if (this.deps.eventLog === undefined) {
36
35
  return messageReplyFromError(new DwnError(
37
- DwnErrorCode.RecordsSubscribeEventStreamUnimplemented,
36
+ DwnErrorCode.RecordsSubscribeEventLogUnimplemented,
38
37
  'Subscriptions are not supported'
39
38
  ), 501);
40
39
  }
@@ -59,8 +58,8 @@ export class RecordsSubscribeHandler implements MethodHandler {
59
58
  } else {
60
59
  // authentication and authorization
61
60
  try {
62
- await authenticate(message.authorization!, this.didResolver);
63
- await RecordsSubscribeHandler.authorizeRecordsSubscribe(tenant, recordsSubscribe, this.messageStore);
61
+ await authenticate(message.authorization!, this.deps.didResolver);
62
+ await RecordsSubscribeHandler.authorizeRecordsSubscribe(tenant, recordsSubscribe, this.deps.messageStore, this.deps.coreProtocols);
64
63
  } catch (error) {
65
64
  return messageReplyFromError(error, 401);
66
65
  }
@@ -74,30 +73,51 @@ export class RecordsSubscribeHandler implements MethodHandler {
74
73
  }
75
74
  }
76
75
 
77
- // Step 1: Register event listener FIRST to ensure no events are missed between query and subscribe
78
- const listener: EventListener = (eventTenant, event, eventIndexes):void => {
79
- if (tenant === eventTenant && FilterUtility.matchAnyFilter(eventIndexes, eventFilters)) {
80
- subscriptionHandler(event as RecordEvent);
76
+ const messageCid = await Message.getCid(message);
77
+ const { cursor: eventLogCursor } = recordsSubscribe.message.descriptor;
78
+
79
+ if (eventLogCursor !== undefined) {
80
+ // ---- Cursor mode: catch-up from EventLog + EOSE + live ----
81
+ // All catch-up, buffering, dedup, and EOSE delivery are handled by the
82
+ // EventLog implementation. The handler just passes the cursor and filters.
83
+ // The subscriptionHandler receives SubscriptionMessage (event + EOSE) directly.
84
+
85
+ try {
86
+ const subscription = await this.deps.eventLog!.subscribe(tenant, messageCid, subscriptionHandler, {
87
+ cursor : eventLogCursor,
88
+ filters : eventFilters,
89
+ });
90
+
91
+ return {
92
+ status: { code: 200, detail: 'OK' },
93
+ subscription,
94
+ };
95
+ } catch (error) {
96
+ return messageReplyFromError(error, 500);
81
97
  }
82
- };
98
+ }
83
99
 
84
- const messageCid = await Message.getCid(message);
85
- const subscription = await this.eventStream.subscribe(tenant, messageCid, listener);
100
+ // ---- No cursor: existing behavior (initial snapshot from MessageStore) ----
101
+
102
+ // Step 1: Register event listener FIRST to ensure no events are missed between query and subscribe
103
+ const subscription = await this.deps.eventLog!.subscribe(tenant, messageCid, subscriptionHandler, {
104
+ filters: eventFilters,
105
+ });
86
106
 
87
107
  // Step 2: Query for initial snapshot of matching records
88
108
  let entries: RecordsQueryReplyEntry[];
89
- let cursor: PaginationCursor | undefined;
109
+ let paginationCursor: PaginationCursor | undefined;
90
110
  try {
91
111
  const { dateSort, pagination } = recordsSubscribe.message.descriptor;
92
112
  const messageSort = RecordsSubscribeHandler.convertDateSort(dateSort);
93
- const queryResult = await this.messageStore.query(tenant, queryFilters, messageSort, pagination);
113
+ const queryResult = await this.deps.messageStore.query(tenant, queryFilters, messageSort, pagination);
94
114
  entries = queryResult.messages as RecordsQueryReplyEntry[];
95
- cursor = queryResult.cursor;
115
+ paginationCursor = queryResult.cursor;
96
116
 
97
117
  // attach initialWrite for non-initial writes
98
118
  for (const entry of entries) {
99
119
  if (!await RecordsWrite.isInitialWrite(entry)) {
100
- const initialWriteResult = await this.messageStore.query(
120
+ const initialWriteResult = await this.deps.messageStore.query(
101
121
  tenant,
102
122
  [{ recordId: entry.recordId, isLatestBaseState: false, method: DwnMethodName.Write }]
103
123
  );
@@ -114,10 +134,10 @@ export class RecordsSubscribeHandler implements MethodHandler {
114
134
 
115
135
  // Step 3: Return subscription + initial entries + cursor
116
136
  return {
117
- status: { code: 200, detail: 'OK' },
137
+ status : { code: 200, detail: 'OK' },
118
138
  subscription,
119
139
  entries,
120
- cursor
140
+ cursor : paginationCursor,
121
141
  };
122
142
  }
123
143
 
@@ -300,7 +320,8 @@ export class RecordsSubscribeHandler implements MethodHandler {
300
320
  public static async authorizeRecordsSubscribe(
301
321
  tenant: string,
302
322
  recordsSubscribe: RecordsSubscribe,
303
- messageStore: MessageStore
323
+ messageStore: MessageStore,
324
+ coreProtocols?: CoreProtocolRegistry,
304
325
  ): Promise<void> {
305
326
 
306
327
  if (Message.isSignedByAuthorDelegate(recordsSubscribe.message)) {
@@ -311,7 +332,7 @@ export class RecordsSubscribeHandler implements MethodHandler {
311
332
  // this is because we dynamically filter out records that the caller is not authorized to see.
312
333
  // Currently only run protocol authorization if message deliberately invokes a protocol role.
313
334
  if (Records.shouldProtocolAuthorize(recordsSubscribe.signaturePayload!)) {
314
- await ProtocolAuthorization.authorizeQueryOrSubscribe(tenant, recordsSubscribe, messageStore);
335
+ await ProtocolAuthorization.authorizeQueryOrSubscribe(tenant, recordsSubscribe, messageStore, coreProtocols);
315
336
  }
316
337
  }
317
338
  }
@@ -1,10 +1,7 @@
1
- import type { DataStore } from '../types/data-store.js';
2
- import type { DidResolver } from '@enbox/dids';
3
- import type { EventStream } from '../types/subscriptions.js';
1
+ import type { Filter } from '../types/query-types.js';
4
2
  import type { GenericMessageReply } from '../types/message-types.js';
5
3
  import type { MessageStore } from '../types/message-store.js';
6
- import type { MethodHandler } from '../types/method-handler.js';
7
- import type { StateIndex } from '../types/state-index.js';
4
+ import type { HandlerDependencies, MethodHandler } from '../types/method-handler.js';
8
5
  import type { RecordsQueryReplyEntry, RecordsWriteMessage } from '../types/records-types.js';
9
6
 
10
7
  import { authenticate } from '../core/auth.js';
@@ -12,12 +9,16 @@ import { Cid } from '../utils/cid.js';
12
9
  import { DataStream } from '../utils/data-stream.js';
13
10
  import { DwnConstant } from '../core/dwn-constant.js';
14
11
  import { Encoder } from '../utils/encoder.js';
12
+ import { FilterUtility } from '../utils/filter.js';
15
13
  import { Message } from '../core/message.js';
16
14
  import { messageReplyFromError } from '../core/message-reply.js';
17
15
  import { PermissionsProtocol } from '../protocols/permissions.js';
18
16
  import { ProtocolAuthorization } from '../core/protocol-authorization.js';
17
+ import { Records } from '../utils/records.js';
19
18
  import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
20
19
  import { RecordsWrite } from '../interfaces/records-write.js';
20
+ import { ResumableTaskName } from '../core/resumable-task-manager.js';
21
+ import { SortDirection } from '../types/query-types.js';
21
22
  import { StorageController } from '../store/storage-controller.js';
22
23
  import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
23
24
  import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
@@ -26,13 +27,7 @@ type HandlerArgs = { tenant: string, message: RecordsWriteMessage, dataStream?:
26
27
 
27
28
  export class RecordsWriteHandler implements MethodHandler {
28
29
 
29
- constructor(
30
- private didResolver: DidResolver,
31
- private messageStore: MessageStore,
32
- private dataStore: DataStore,
33
- private stateIndex: StateIndex,
34
- private eventStream?: EventStream
35
- ) { }
30
+ constructor(private deps: HandlerDependencies) { }
36
31
 
37
32
  public async handle({
38
33
  tenant,
@@ -43,18 +38,15 @@ export class RecordsWriteHandler implements MethodHandler {
43
38
  try {
44
39
  recordsWrite = await RecordsWrite.parse(message);
45
40
 
46
- // Protocol-authorized record specific validation
47
- if (message.descriptor.protocol !== undefined) {
48
- await ProtocolAuthorization.validateReferentialIntegrity(tenant, recordsWrite, this.messageStore);
49
- }
41
+ await ProtocolAuthorization.validateReferentialIntegrity(tenant, recordsWrite, this.deps.messageStore, this.deps.coreProtocols);
50
42
  } catch (e) {
51
43
  return messageReplyFromError(e, 400);
52
44
  }
53
45
 
54
46
  // authentication & authorization
55
47
  try {
56
- await authenticate(message.authorization, this.didResolver, message.attestation);
57
- await RecordsWriteHandler.authorizeRecordsWrite(tenant, recordsWrite, this.messageStore);
48
+ await authenticate(message.authorization, this.deps.didResolver, message.attestation);
49
+ await this.authorizeRecordsWrite(tenant, recordsWrite, this.deps.messageStore);
58
50
  } catch (e) {
59
51
  return messageReplyFromError(e, 401);
60
52
  }
@@ -64,7 +56,7 @@ export class RecordsWriteHandler implements MethodHandler {
64
56
  interface : DwnInterfaceName.Records,
65
57
  recordId : message.recordId
66
58
  };
67
- const { messages: existingMessages } = await this.messageStore.query(tenant, [ query ]);
59
+ const { messages: existingMessages } = await this.deps.messageStore.query(tenant, [ query ]);
68
60
 
69
61
  // if the incoming write is not the initial write, then it must not modify any immutable properties defined by the initial write
70
62
  const newMessageIsInitialWrite = await recordsWrite.isInitialWrite();
@@ -78,6 +70,15 @@ export class RecordsWriteHandler implements MethodHandler {
78
70
  }
79
71
  }
80
72
 
73
+ // Squash backstop: if the protocol path has $squash: true, reject any write whose
74
+ // messageTimestamp is <= the most recent squash record at the same path and parent context.
75
+ // The squash record acts as a temporal floor — no record older than the latest squash can exist.
76
+ try {
77
+ await this.enforceSquashBackstop(tenant, message);
78
+ } catch (e) {
79
+ return messageReplyFromError(e, 409);
80
+ }
81
+
81
82
  const newestExistingMessage = await Message.getNewestMessage(existingMessages);
82
83
 
83
84
  let incomingMessageIsNewest = false;
@@ -95,6 +96,12 @@ export class RecordsWriteHandler implements MethodHandler {
95
96
  };
96
97
  }
97
98
 
99
+ // Look up the core protocol (if any) for the incoming message so that lifecycle hooks
100
+ // can be dispatched generically rather than checking for specific protocol URIs.
101
+ const coreProtocol = message.descriptor.protocol !== undefined
102
+ ? this.deps.coreProtocols?.get(message.descriptor.protocol)
103
+ : undefined;
104
+
98
105
  try {
99
106
  if (newestExistingMessage?.descriptor.method === DwnMethodName.Delete) {
100
107
  throw new DwnError(
@@ -103,11 +110,12 @@ export class RecordsWriteHandler implements MethodHandler {
103
110
  );
104
111
  }
105
112
 
106
- // NOTE: We want to perform additional validation before storing the RecordsWrite.
107
- // This is necessary for core DWN RecordsWrite that needs additional processing and allows us to fail before the storing and post processing.
108
- //
109
- // Example: Ensures that the protocol tag of a permission revocation RecordsWrite and the parent grant's scoped protocol match.
110
- await this.preProcessingForCoreRecordsWrite(tenant, message);
113
+ // Dispatch pre-processing hooks to the core protocol, if applicable.
114
+ // This allows core protocols to perform cross-record validation before storage
115
+ // (e.g. ensuring revocation tag consistency with the parent grant's scoped protocol).
116
+ if (coreProtocol?.preProcessWrite !== undefined) {
117
+ await coreProtocol.preProcessWrite(tenant, message, this.deps.messageStore);
118
+ }
111
119
 
112
120
  // NOTE: We allow isLatestBaseState to be true ONLY if the incoming message comes with data, or if the incoming message is NOT an initial write
113
121
  // This would allow an initial write to be written to the DB without data, but having it not queryable,
@@ -133,14 +141,14 @@ export class RecordsWriteHandler implements MethodHandler {
133
141
  }
134
142
 
135
143
  const indexes = await recordsWrite.constructIndexes(isLatestBaseState);
136
- await this.messageStore.put(tenant, messageWithOptionalEncodedData, indexes);
137
- await this.stateIndex.insert(tenant, await Message.getCid(message), indexes);
144
+ await this.deps.messageStore.put(tenant, messageWithOptionalEncodedData, indexes);
145
+ await this.deps.stateIndex!.insert(tenant, await Message.getCid(message), indexes);
138
146
 
139
147
  // NOTE: We only emit a `RecordsWrite` when the message is the latest base state.
140
148
  // Because we allow a `RecordsWrite` which is not the latest state to be written, but not queried, we shouldn't emit it either.
141
149
  // It will be emitted as a part of a subsequent next write, if it is the latest base state.
142
- if (this.eventStream !== undefined && isLatestBaseState) {
143
- this.eventStream.emit(tenant, { message, initialWrite }, indexes);
150
+ if (this.deps.eventLog !== undefined && isLatestBaseState) {
151
+ await this.deps.eventLog.emit(tenant, { message, initialWrite }, indexes);
144
152
  }
145
153
  } catch (error) {
146
154
  if (error instanceof DwnError) {
@@ -149,8 +157,8 @@ export class RecordsWriteHandler implements MethodHandler {
149
157
  error.code === DwnErrorCode.RecordsWriteNotAllowedAfterDelete ||
150
158
  error.code === DwnErrorCode.RecordsWriteDataCidMismatch ||
151
159
  error.code === DwnErrorCode.RecordsWriteDataSizeMismatch ||
152
- error.code.startsWith('PermissionsProtocolValidate') ||
153
- error.code.startsWith('SchemaValidator')) {
160
+ error.code.startsWith('SchemaValidator') ||
161
+ this.deps.coreProtocols?.mapErrorToStatusCode(error.code) !== undefined) {
154
162
  return messageReplyFromError(error, 400);
155
163
  }
156
164
  }
@@ -170,93 +178,31 @@ export class RecordsWriteHandler implements MethodHandler {
170
178
 
171
179
  // delete all existing messages of the same record that are not newest, except for the initial write
172
180
  await StorageController.deleteAllOlderMessagesButKeepInitialWrite(
173
- tenant, existingMessages, newestMessage, this.messageStore, this.dataStore, this.stateIndex
181
+ tenant, existingMessages, newestMessage, this.deps.messageStore, this.deps.dataStore!, this.deps.stateIndex!
174
182
  );
175
183
 
176
- await this.postProcessingForCoreRecordsWrite(tenant, recordsWrite);
177
-
178
- return messageReply;
179
- };
180
-
181
- /**
182
- * Performs additional necessary validation before storing the RecordsWrite if it is a core DWN RecordsWrite that needs additional processing.
183
- * For instance: a Permission revocation RecordsWrite.
184
- */
185
- private async preProcessingForCoreRecordsWrite(tenant: string, recordsWriteMessage: RecordsWriteMessage): Promise<void> {
186
-
187
- // we validate the protocol tag of the revocation message against the grant's scoped protocol
188
- // to do this we will fetch the grant, and compare the the scoped protocol value to the protocol tag of the revocation message
189
- if (recordsWriteMessage.descriptor.protocol === PermissionsProtocol.uri &&
190
- recordsWriteMessage.descriptor.protocolPath === PermissionsProtocol.revocationPath) {
191
-
192
- // get the parentId of the revocation message, which is the permissionGrantId
193
- // fetch the grant in order to get the grant's protocol
194
- const permissionGrantId = recordsWriteMessage.descriptor.parentId!;
195
- const grant = await PermissionsProtocol.fetchGrant(tenant, this.messageStore, permissionGrantId);
196
-
197
- // get the protocol values of the revocation message from the protocol tag and the protocol from the grant scope if they are defined
198
- // compare the two values ensuring they must match
199
- const revokeTagProtocol = recordsWriteMessage.descriptor.tags?.protocol;
200
- const grantProtocol = 'protocol' in grant.scope ? grant.scope.protocol : undefined;
201
- if (grantProtocol !== revokeTagProtocol) {
202
- throw new DwnError(
203
- DwnErrorCode.PermissionsProtocolValidateRevocationProtocolTagMismatch,
204
- `Revocation protocol ${revokeTagProtocol} does not match grant protocol ${grantProtocol}`
205
- );
206
- }
207
- }
208
- }
209
-
210
- private static validateSchemaForCoreRecordsWrite(recordsWriteMessage: RecordsWriteMessage, dataBytes: Uint8Array): void {
211
- if (recordsWriteMessage.descriptor.protocol === PermissionsProtocol.uri) {
212
- PermissionsProtocol.validateSchema(recordsWriteMessage, dataBytes);
213
- }
214
- }
215
-
216
- /**
217
- * Performs additional necessary tasks if the RecordsWrite handled is a core DWN RecordsWrite that need additional processing.
218
- * For instance: when a Permission revocation is written, all messages authorized by the revoked grant
219
- * that were created after the revocation timestamp are deleted from all stores.
220
- */
221
- private async postProcessingForCoreRecordsWrite(tenant: string, recordsWrite: RecordsWrite): Promise<void> {
222
- if (recordsWrite.message.descriptor.protocol !== PermissionsProtocol.uri ||
223
- recordsWrite.message.descriptor.protocolPath !== PermissionsProtocol.revocationPath) {
224
- return;
225
- }
226
-
227
- // Delete all messages authorized by the revoked grant that were created after the revocation.
228
- // `permissionGrantId` is indexed via the RecordsWriteDescriptor spread in constructIndexes().
229
- const permissionGrantId = recordsWrite.message.descriptor.parentId!;
230
- const grantAuthorizedMessagesQuery = {
231
- permissionGrantId,
232
- dateCreated: { gte: recordsWrite.message.descriptor.messageTimestamp },
233
- };
234
- const { messages: grantAuthorizedMessages } = await this.messageStore.query(tenant, [grantAuthorizedMessagesQuery]);
235
-
236
- if (grantAuthorizedMessages.length === 0) {
237
- return;
184
+ // Squash processing: if the incoming write is a squash, delete all older sibling records
185
+ // at the same protocol path and parent context. Uses the resumable task system for crash safety.
186
+ if (message.descriptor.squash === true) {
187
+ await this.deps.resumableTaskManager!.run({
188
+ name : ResumableTaskName.RecordsSquash,
189
+ data : { tenant, message }
190
+ });
238
191
  }
239
192
 
240
- // Delete data from the data store first to avoid orphaned data blobs in case of crash.
241
- // Only RecordsWrite messages with data larger than maxDataSizeAllowedToBeEncoded have data in the data store.
242
- for (const message of grantAuthorizedMessages) {
243
- if (message.descriptor.method === DwnMethodName.Write) {
244
- const recordsWriteMessage = message as RecordsWriteMessage;
245
- if (recordsWriteMessage.descriptor.dataSize > DwnConstant.maxDataSizeAllowedToBeEncoded) {
246
- await this.dataStore.delete(tenant, recordsWriteMessage.recordId, recordsWriteMessage.descriptor.dataCid);
247
- }
248
- }
193
+ // Dispatch post-processing hooks to the core protocol, if applicable.
194
+ // This allows core protocols to perform cascading side effects after a successful write
195
+ // (e.g. deleting messages authorized by a revoked grant).
196
+ if (coreProtocol?.postProcessWrite !== undefined) {
197
+ await coreProtocol.postProcessWrite(tenant, recordsWrite, {
198
+ messageStore : this.deps.messageStore,
199
+ dataStore : this.deps.dataStore!,
200
+ stateIndex : this.deps.stateIndex!,
201
+ });
249
202
  }
250
203
 
251
- // Compute CIDs for all messages to delete.
252
- const messageCids = await Promise.all(grantAuthorizedMessages.map((message): Promise<string> => Message.getCid(message)));
253
-
254
- // Delete from state index before message store so we don't have orphaned state entries.
255
- await this.stateIndex.delete(tenant, messageCids);
256
-
257
- // Finally delete all messages from the message store.
258
- await Promise.all(messageCids.map((cid): Promise<void> => this.messageStore.delete(tenant, cid)));
259
- }
204
+ return messageReply;
205
+ };
260
206
 
261
207
  /**
262
208
  * Returns a `RecordsQueryReplyEntry` with a copy of the incoming message and the incoming data encoded to `Base64URL`.
@@ -281,7 +227,13 @@ export class RecordsWriteHandler implements MethodHandler {
281
227
  const dataCid = await Cid.computeDagPbCidFromBytes(dataBytes);
282
228
  RecordsWriteHandler.validateDataIntegrity(message.descriptor.dataCid, message.descriptor.dataSize, dataCid, dataBytes.length);
283
229
 
284
- RecordsWriteHandler.validateSchemaForCoreRecordsWrite(message, dataBytes);
230
+ // Dispatch schema validation to the core protocol, if applicable.
231
+ const coreProtocol = message.descriptor.protocol !== undefined
232
+ ? this.deps.coreProtocols?.get(message.descriptor.protocol)
233
+ : undefined;
234
+ if (coreProtocol?.validateRecord !== undefined) {
235
+ coreProtocol.validateRecord(message, dataBytes);
236
+ }
285
237
 
286
238
  messageWithOptionalEncodedData = await this.cloneAndAddEncodedData(message, dataBytes);
287
239
  } else {
@@ -292,13 +244,13 @@ export class RecordsWriteHandler implements MethodHandler {
292
244
  // perform storage and CID computation in parallel
293
245
  const [dataCid, DataStorePutResult] = await Promise.all([
294
246
  Cid.computeDagPbCidFromStream(dataStreamCopy1),
295
- this.dataStore.put(tenant, message.recordId, message.descriptor.dataCid, dataStreamCopy2)
247
+ this.deps.dataStore!.put(tenant, message.recordId, message.descriptor.dataCid, dataStreamCopy2)
296
248
  ]);
297
249
 
298
250
  RecordsWriteHandler.validateDataIntegrity(message.descriptor.dataCid, message.descriptor.dataSize, dataCid, DataStorePutResult.dataSize);
299
251
  } catch (error) {
300
252
  // unwind/delete data if we have issue with storage or the data failed integrity validation
301
- await this.dataStore.delete(tenant, message.recordId, message.descriptor.dataCid);
253
+ await this.deps.dataStore!.delete(tenant, message.recordId, message.descriptor.dataCid);
302
254
 
303
255
  throw error;
304
256
  }
@@ -335,7 +287,7 @@ export class RecordsWriteHandler implements MethodHandler {
335
287
  // else just make sure the data is in the data store
336
288
 
337
289
  // attempt to retrieve the data from the previous message
338
- const DataStoreGetResult = await this.dataStore.get(tenant, newestExistingWrite.recordId, message.descriptor.dataCid);
290
+ const DataStoreGetResult = await this.deps.dataStore!.get(tenant, newestExistingWrite.recordId, message.descriptor.dataCid);
339
291
 
340
292
  if (DataStoreGetResult === undefined) {
341
293
  throw new DwnError(
@@ -377,7 +329,90 @@ export class RecordsWriteHandler implements MethodHandler {
377
329
  }
378
330
  }
379
331
 
380
- private static async authorizeRecordsWrite(tenant: string, recordsWrite: RecordsWrite, messageStore: MessageStore): Promise<void> {
332
+ /**
333
+ * Enforces the squash backstop: if the incoming message is at a protocol path with `$squash: true`,
334
+ * and there exists a squash record at the same protocol path and parent context whose
335
+ * `messageTimestamp` is >= the incoming message's `messageTimestamp`, reject with 409.
336
+ *
337
+ * This check only applies to protocol-based records at `$squash: true` paths.
338
+ */
339
+ private async enforceSquashBackstop(tenant: string, message: RecordsWriteMessage): Promise<void> {
340
+ // Only applies to protocol-based records
341
+ if (message.descriptor.protocol === undefined || message.descriptor.protocolPath === undefined) {
342
+ return;
343
+ }
344
+
345
+ // Fetch the protocol definition to check if $squash is enabled at this path.
346
+ // Pass coreProtocols so that core protocols (e.g. permissions) are resolved from the registry.
347
+ let protocolDefinition;
348
+ try {
349
+ protocolDefinition = await ProtocolAuthorization.fetchProtocolDefinition(
350
+ tenant,
351
+ message.descriptor.protocol,
352
+ this.deps.messageStore,
353
+ undefined,
354
+ this.deps.coreProtocols,
355
+ );
356
+ } catch (error) {
357
+ // If the protocol definition can't be found, skip the backstop check.
358
+ // Authorization will handle the missing protocol error later.
359
+ console.warn(`enforceSquashBackstop: failed to fetch protocol definition for '${message.descriptor.protocol}':`, error);
360
+ return;
361
+ }
362
+
363
+ // Walk the structure to find the rule set for this protocol path
364
+ const pathSegments = message.descriptor.protocolPath.split('/');
365
+ let ruleSet = protocolDefinition.structure[pathSegments[0]];
366
+ for (let i = 1; i < pathSegments.length && ruleSet !== undefined; i++) {
367
+ ruleSet = ruleSet[pathSegments[i]] as typeof ruleSet;
368
+ }
369
+
370
+ if (ruleSet === undefined || ruleSet.$squash !== true) {
371
+ return;
372
+ }
373
+
374
+ // Find the most recent squash record at the same protocol path and parent context
375
+ const filter: Filter = {
376
+ interface : DwnInterfaceName.Records,
377
+ method : DwnMethodName.Write,
378
+ isLatestBaseState : true,
379
+ protocol : message.descriptor.protocol,
380
+ protocolPath : message.descriptor.protocolPath,
381
+ squash : true,
382
+ };
383
+
384
+ // Scope by parent context for nested records
385
+ const parentContextId = Records.getParentContextFromOfContextId(message.contextId);
386
+ if (parentContextId !== undefined && parentContextId !== '') {
387
+ const prefixFilter = FilterUtility.constructPrefixFilterAsRangeFilter(parentContextId);
388
+ filter.contextId = prefixFilter;
389
+ }
390
+
391
+ const { messages: squashMessages } = await this.deps.messageStore.query(
392
+ tenant,
393
+ [filter],
394
+ { messageTimestamp: SortDirection.Descending },
395
+ { limit: 1 },
396
+ );
397
+
398
+ if (squashMessages.length === 0) {
399
+ return;
400
+ }
401
+
402
+ const newestSquash = squashMessages[0] as RecordsWriteMessage;
403
+
404
+ // Reject if the incoming message's timestamp is <= the squash record's timestamp
405
+ if (message.descriptor.messageTimestamp <= newestSquash.descriptor.messageTimestamp) {
406
+ throw new DwnError(
407
+ DwnErrorCode.ProtocolAuthorizationSquashBackstop,
408
+ `incoming message timestamp '${message.descriptor.messageTimestamp}' is not newer than ` +
409
+ `the most recent squash record timestamp '${newestSquash.descriptor.messageTimestamp}' ` +
410
+ `at protocol path '${message.descriptor.protocolPath}'.`
411
+ );
412
+ }
413
+ }
414
+
415
+ private async authorizeRecordsWrite(tenant: string, recordsWrite: RecordsWrite, messageStore: MessageStore): Promise<void> {
381
416
  // if owner signature is given (`owner` is not `undefined`), it must be the same as the tenant DID
382
417
  if (recordsWrite.owner !== undefined && recordsWrite.owner !== tenant) {
383
418
  throw new DwnError(
@@ -410,10 +445,8 @@ export class RecordsWriteHandler implements MethodHandler {
410
445
  permissionGrant,
411
446
  messageStore
412
447
  });
413
- } else if (recordsWrite.message.descriptor.protocol !== undefined) {
414
- await ProtocolAuthorization.authorizeWrite(tenant, recordsWrite, messageStore);
415
448
  } else {
416
- throw new DwnError(DwnErrorCode.RecordsWriteAuthorizationFailed, 'message failed authorization');
449
+ await ProtocolAuthorization.authorizeWrite(tenant, recordsWrite, messageStore, this.deps.coreProtocols);
417
450
  }
418
451
  }
419
452
  }
package/src/index.ts CHANGED
@@ -1,13 +1,17 @@
1
1
  // export everything that we want to be consumable
2
2
  export type { DwnConfig } from './dwn.js';
3
- export type { EventListener, EventStream, EventSubscription, MessageEvent, SubscriptionReply } from './types/subscriptions.js';
3
+ export type { EventListener, EventLog, EventLogEntry, EventLogReadOptions, EventLogReadResult, EventLogSubscribeOptions, EventSubscription, MessageEvent, SubscriptionEose, SubscriptionEvent, SubscriptionListener, SubscriptionMessage, SubscriptionReply } from './types/subscriptions.js';
4
4
  export type { AuthorizationModel, Descriptor, DelegatedGrantRecordsWriteMessage, GenericMessage, GenericMessageReply, GenericSignaturePayload, MessageSort, MessageSubscription, Pagination, QueryResultEntry, Status } from './types/message-types.js';
5
5
  export type { MessagesFilter, MessagesReadMessage as MessagesReadMessage, MessagesReadReply as MessagesReadReply, MessagesReadReplyEntry as MessagesReadReplyEntry, MessagesReadDescriptor, MessagesSubscribeDescriptor, MessagesSubscribeMessage, MessagesSubscribeReply, MessageSubscriptionHandler, MessagesSubscribeMessageOptions, MessagesSyncAction, MessagesSyncDescriptor, MessagesSyncMessage, MessagesSyncReply } from './types/messages-types.js';
6
6
  export type { GT, LT, Filter, FilterValue, KeyValues, EqualFilter, OneOfFilter, RangeFilter, RangeCriterion, PaginationCursor, QueryOptions, RangeValue, StartsWithFilter } from './types/query-types.js';
7
- export type { ProtocolsConfigureDescriptor, ProtocolDefinition, ProtocolTypes, ProtocolRuleSet, ProtocolsQueryFilter, ProtocolsConfigureMessage, ProtocolsQueryMessage, ProtocolsQueryReply, ProtocolActionRule, ProtocolPathEncryption, ProtocolsQueryDescriptor, ProtocolSizeDefinition, ProtocolTagsDefinition, ProtocolTagSchema, ProtocolType, ProtocolUses } from './types/protocols-types.js';
7
+ export type { ProtocolsConfigureDescriptor, ProtocolDefinition, ProtocolTypes, ProtocolRuleSet, ProtocolsQueryFilter, ProtocolsConfigureMessage, ProtocolsQueryMessage, ProtocolsQueryReply, ProtocolActionRule, ProtocolDeliveryStrategy, ProtocolPathEncryption, ProtocolsQueryDescriptor, ProtocolRecordLimitDefinition, ProtocolSizeDefinition, ProtocolTagsDefinition, ProtocolTagSchema, ProtocolType, ProtocolUses } from './types/protocols-types.js';
8
+ export { ProtocolRecordLimitStrategy } from './types/protocols-types.js';
8
9
  export type { DataEncodedRecordsWriteMessage, RecordsCountDescriptor, RecordsCountMessage, RecordsCountReply, RecordsDeleteMessage, RecordsFilter, RecordsQueryMessage, RecordsQueryReply, RecordsQueryReplyEntry, RecordsReadMessage, RecordsReadReply, RecordsSubscribeDescriptor, RecordsSubscribeMessage, RecordsSubscribeReply, RecordSubscriptionHandler, RecordsWriteDescriptor, RecordsWriteTags, RecordsWriteTagValue, RecordsWriteMessage, RecordsWriteSignaturePayload, RecordsDeleteDescriptor, RecordsQueryDescriptor, RecordsReadDescriptor, RecordsSubscribeMessageOptions, RecordsWriteMessageOptions, InternalRecordsWriteMessage, RecordEvent, RecordsWriteTagsFilter } from './types/records-types.js';
9
10
  export type { GeneralJws, SignatureEntry } from './types/jws-types.js';
10
11
  export { authenticate } from './core/auth.js';
12
+ export { CoreProtocolRegistry } from './core/core-protocol.js';
13
+ export { PERMISSIONS_REVOCATION_PATH } from './core/constants.js';
14
+ export type { CoreProtocol, CoreProtocolStores } from './core/core-protocol.js';
11
15
  export { AllowAllTenantGate } from './core/tenant-gate.js';
12
16
  export type { ActiveTenantCheckResult, TenantGate } from './core/tenant-gate.js';
13
17
  export { Cid } from './utils/cid.js';
@@ -72,7 +76,7 @@ export { Time } from './utils/time.js';
72
76
  export * from './types/permission-types.js';
73
77
  export * from './types/records-types.js';
74
78
 
75
- // concrete implementations of stores and event stream
79
+ // concrete implementations of stores and event log
76
80
  export { BlockstoreLevel } from './store/blockstore-level.js';
77
81
  export type { BlockstoreLevelConfig } from './store/blockstore-level.js';
78
82
  export { DataStoreLevel } from './store/data-store-level.js';
@@ -85,8 +89,8 @@ export { MessageStoreLevel } from './store/message-store-level.js';
85
89
  export type { MessageStoreLevelConfig } from './store/message-store-level.js';
86
90
  export { ResumableTaskStoreLevel } from './store/resumable-task-store-level.js';
87
91
  export type { ResumableTaskStoreLevelConfig } from './store/resumable-task-store-level.js';
88
- export { EventEmitterStream } from './event-stream/event-emitter-stream.js';
89
- export type { EventEmitterStreamConfig } from './event-stream/event-emitter-stream.js';
92
+ export { EventEmitterEventLog } from './event-stream/event-emitter-event-log.js';
93
+ export type { EventEmitterEventLogConfig } from './event-stream/event-emitter-event-log.js';
90
94
 
91
95
  // Sparse Merkle Tree and StateIndex
92
96
  export type { StateIndex } from './types/state-index.js';
@@ -13,8 +13,13 @@ import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.j
13
13
  export type MessagesSubscribeOptions = {
14
14
  signer: MessageSigner;
15
15
  messageTimestamp?: string;
16
- filters?: MessagesFilter[]
16
+ filters?: MessagesFilter[];
17
17
  permissionGrantId?: string;
18
+ /**
19
+ * Opaque EventLog cursor string to resume from. When provided, catch-up events are
20
+ * replayed from the EventLog and an EOSE marker is delivered before live events.
21
+ */
22
+ cursor?: string;
18
23
  };
19
24
 
20
25
  export class MessagesSubscribe extends AbstractMessage<MessagesSubscribeMessage> {
@@ -48,6 +53,7 @@ export class MessagesSubscribe extends AbstractMessage<MessagesSubscribeMessage>
48
53
  filters : options.filters ?? [],
49
54
  messageTimestamp : options.messageTimestamp ?? currentTime,
50
55
  permissionGrantId : options.permissionGrantId,
56
+ cursor : options.cursor,
51
57
  };
52
58
 
53
59
  removeUndefinedProperties(descriptor);