@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
@@ -0,0 +1,127 @@
1
+ import type { GenericMessage } from './message-types.js';
2
+ import type { PermissionGrant } from '../protocols/permission-grant.js';
3
+ import type { ProtocolDefinition } from './protocols-types.js';
4
+ import type { RecordsWrite } from '../interfaces/records-write.js';
5
+ import type { RecordsWriteMessage } from './records-types.js';
6
+
7
+ /**
8
+ * The single narrow surface through which validation logic reads state.
9
+ *
10
+ * Every validation-time state read performed during message admission routes through this
11
+ * interface, so the replay basis (initial writes ∪ latest states ∪ tombstones ∪ protocol-config
12
+ * history ∪ permission records) provably stays closed under admission's read set. Validation
13
+ * modules (`core/protocol-authorization*`, `protocols/permissions*`) are lint-banned from
14
+ * importing `MessageStore` directly; a new protocol-engine feature that needs new state must add
15
+ * a reader method here.
16
+ */
17
+ export interface ValidationStateReader {
18
+ /**
19
+ * Fetches a record's initial `RecordsWrite` by entry ID, parsed.
20
+ * @returns the initial write, or `undefined` when no message carries the entry ID.
21
+ */
22
+ fetchInitialRecordsWrite(tenant: string, recordId: string): Promise<RecordsWrite | undefined>;
23
+
24
+ /**
25
+ * Fetches a record's initial write from among all of the record's writes.
26
+ * @returns the initial write message, or `undefined` when the record has no messages at all.
27
+ * @throws {DwnError} with `RecordsWriteGetInitialWriteNotFound` when writes exist for the
28
+ * record but none of them is the initial write.
29
+ */
30
+ fetchInitialWrite(tenant: string, recordId: string): Promise<RecordsWriteMessage | undefined>;
31
+
32
+ /**
33
+ * Constructs the chain of existing records from the root to the given
34
+ * descendant, each represented by its initial `RecordsWrite`.
35
+ * @returns the chain root-first; an empty array when `descendantRecordId` is `undefined`.
36
+ * @throws {DwnError} with `ProtocolAuthorizationParentNotFoundConstructingRecordChain` when any
37
+ * link in the chain is missing.
38
+ */
39
+ constructRecordChain(tenant: string, descendantRecordId: string | undefined): Promise<RecordsWriteMessage[]>;
40
+
41
+ /**
42
+ * Fetches the immediate parent record for protocolPath/contextId verification.
43
+ *
44
+ * Queries the latest-state write first — the fast path that excludes deleted parents. If no
45
+ * latest write exists, a retained initial write is sufficient for immutable parent facts
46
+ * (protocolPath/contextId) provided no local tombstone exists for that record.
47
+ * @returns the parent write, or `undefined` when the parent is absent (or deleted).
48
+ */
49
+ fetchParentRecord(input: {
50
+ tenant: string;
51
+ parentProtocolUri: string;
52
+ parentId: string;
53
+ }): Promise<RecordsWriteMessage | undefined>;
54
+
55
+ /**
56
+ * Checks whether a role record matching the invoked-role selector exists.
57
+ * Filter-only — role validation never reads record data. The latest-state match is the fast
58
+ * path. If no latest match exists, a retained initial role write is sufficient for immutable
59
+ * role facts (recipient/path/context) provided no local tombstone exists for that role record.
60
+ */
61
+ hasMatchingRoleRecord(input: {
62
+ tenant: string;
63
+ protocol: string;
64
+ protocolPath: string;
65
+ recipient: string;
66
+ contextIdPrefix?: string;
67
+ }): Promise<boolean>;
68
+
69
+ /**
70
+ * Queries the latest-state role records matching the given
71
+ * selector, used to reject duplicate role assignments to the same recipient. Filter-only.
72
+ */
73
+ queryLatestRoleRecords(input: {
74
+ tenant: string;
75
+ protocol: string;
76
+ protocolPath: string;
77
+ recipient: string;
78
+ contextIdPrefix?: string;
79
+ }): Promise<RecordsWriteMessage[]>;
80
+
81
+ /**
82
+ * Fetches the permission grant with the given record ID, with its scope parsed from grant data.
83
+ * @throws {DwnError} with `GrantAuthorizationGrantMissing` when the grant does not exist.
84
+ */
85
+ fetchGrant(tenant: string, permissionGrantId: string): Promise<PermissionGrant>;
86
+
87
+ /**
88
+ * Fetches the oldest latest-state revocation record for the given permission grant, if any.
89
+ * Grant activity checks compare the oldest revocation timestamp to the incoming message timestamp.
90
+ */
91
+ fetchOldestGrantRevocation(tenant: string, permissionGrantId: string): Promise<GenericMessage | undefined>;
92
+
93
+ /**
94
+ * Fetches the newest `RecordsWrite` associated with a record, used to authorize `Messages.Read`
95
+ * access to `RecordsDelete` messages by projecting the delete back to the deleted record's
96
+ * protocol scope.
97
+ * @throws {DwnError} with `RecordsWriteGetNewestWriteRecordNotFound` when no write exists.
98
+ */
99
+ fetchNewestRecordsWrite(tenant: string, recordId: string): Promise<RecordsWriteMessage>;
100
+
101
+ /**
102
+ * Fetches the protocol definition for the given protocol URI.
103
+ * When `messageTimestamp` is provided, returns the definition active at that point in time —
104
+ * the `ProtocolsConfigure` with the greatest `messageTimestamp` that is <= the given timestamp,
105
+ * read from retained config history. When not provided, returns the latest definition.
106
+ * Core protocol definitions are returned from the registry without a store read.
107
+ * @throws {DwnError} with `ProtocolAuthorizationProtocolNotFound` when no definition exists.
108
+ */
109
+ fetchProtocolDefinition(tenant: string, protocolUri: string, messageTimestamp?: string): Promise<ProtocolDefinition>;
110
+
111
+ /**
112
+ * Fetches the latest `$squash: true` record at a protocol path within the parent context.
113
+ * This is the temporal floor used by the squash backstop.
114
+ */
115
+ fetchLatestSquashRecordAtScope(input: {
116
+ tenant: string;
117
+ protocol: string;
118
+ protocolPath: string;
119
+ contextIdPrefix?: string;
120
+ }): Promise<RecordsWriteMessage | undefined>;
121
+
122
+ /**
123
+ * Checks whether the data with the given CID is present in the `DataStore` for the given record.
124
+ * This is the prior-data integrity check for dataless non-initial writes.
125
+ */
126
+ hasStoredData(tenant: string, recordId: string, dataCid: string): Promise<boolean>;
127
+ }
@@ -1,11 +1,15 @@
1
1
  import type { CoreProtocolRegistry } from '../core/core-protocol.js';
2
2
  import type { Filter } from '../types/query-types.js';
3
+ import type { GenericMessage } from '../types/message-types.js';
3
4
  import type { MessagesFilter } from '../types/messages-types.js';
4
5
 
5
6
  import { FilterUtility } from './filter.js';
6
7
  import { normalizeProtocolUrl } from './url.js';
8
+ import { Records } from './records.js';
7
9
  import { isEmptyObject, removeUndefinedProperties } from '@enbox/common';
8
10
 
11
+ type StoredMessageWithEncodedData = GenericMessage & { encodedData?: string };
12
+
9
13
 
10
14
  /**
11
15
  * Class containing Messages related utility methods.
@@ -95,6 +99,22 @@ export class Messages {
95
99
  return messagesQueryFilters;
96
100
  }
97
101
 
102
+ /**
103
+ * Returns a copy of a RecordsWrite message without inline encodedData, and the
104
+ * detached encodedData value for wire surfaces that carry data beside the message.
105
+ */
106
+ public static detachEncodedData(message: GenericMessage): { message: GenericMessage; encodedData?: string } {
107
+ if (!Records.isRecordsWrite(message) || !Messages.hasEncodedData(message)) {
108
+ return { message };
109
+ }
110
+
111
+ const messageWithoutEncodedData: StoredMessageWithEncodedData = { ...message };
112
+ const { encodedData } = messageWithoutEncodedData;
113
+ delete messageWithoutEncodedData.encodedData;
114
+
115
+ return { message: messageWithoutEncodedData, encodedData };
116
+ }
117
+
98
118
  /**
99
119
  * Converts an external-facing filter model into an internal-facing filer model used by data store.
100
120
  */
@@ -132,4 +152,8 @@ export class Messages {
132
152
 
133
153
  return filterCopy;
134
154
  }
135
- }
155
+
156
+ private static hasEncodedData(message: GenericMessage): message is StoredMessageWithEncodedData {
157
+ return 'encodedData' in message && typeof message.encodedData === 'string';
158
+ }
159
+ }
@@ -0,0 +1,377 @@
1
+ import type { MessageStore } from '../types/message-store.js';
2
+ import type { ProtocolRecordLimitDefinition } from '../types/protocols-types.js';
3
+ import type { RecordsWriteMessage } from '../types/records-types.js';
4
+ import type { ValidationStateReader } from '../types/validation-state-reader.js';
5
+ import type { Filter, PaginationCursor } from '../types/query-types.js';
6
+ import type { MessageSort, Pagination } from '../types/message-types.js';
7
+
8
+ import { FilterUtility } from './filter.js';
9
+ import { getRuleSetAtPath } from './protocols.js';
10
+ import { lexicographicalCompare } from './string.js';
11
+ import { ProtocolRecordLimitStrategy } from '../types/protocols-types.js';
12
+ import { Records } from './records.js';
13
+ import { SortDirection } from '../types/query-types.js';
14
+ import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
15
+ import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
16
+
17
+ type RecordLimitOccupancyDependencies = {
18
+ messageStore: MessageStore;
19
+ validationStateReader: ValidationStateReader;
20
+ };
21
+
22
+ type RecordLimitOccupancyQueryInput = RecordLimitOccupancyDependencies & {
23
+ tenant: string;
24
+ filters: Filter[];
25
+ messageTimestamp: string;
26
+ messageSort?: MessageSort;
27
+ pagination?: Pagination;
28
+ };
29
+
30
+ type RecordLimitScope = {
31
+ protocol: string;
32
+ protocolPath: string;
33
+ parentContextId: string;
34
+ };
35
+
36
+ type RecordLimitFilterResolution = {
37
+ projectedFilters: Filter[];
38
+ };
39
+
40
+ /**
41
+ * Queries records with bounded `$recordLimit` occupancy projection when every limited filter targets one concrete scope.
42
+ *
43
+ * Broad filters keep the store's native query path. Projecting those without a store-level grouping primitive would require
44
+ * scanning the full matching set, which is worse than leaving them unprojected until a bounded broad-query strategy exists.
45
+ */
46
+ export async function queryRecordsWithRecordLimitOccupancy(
47
+ input: RecordLimitOccupancyQueryInput
48
+ ): Promise<{ messages: RecordsWriteMessage[]; cursor?: PaginationCursor }> {
49
+ const filterResolution = await resolveRecordLimitFilters(input);
50
+ if (filterResolution === undefined) {
51
+ const { messages, cursor } = await input.messageStore.query(input.tenant, input.filters, input.messageSort, input.pagination);
52
+ return { messages: messages.filter(Records.isRecordsWrite), cursor };
53
+ }
54
+
55
+ if (filterResolution.projectedFilters.length === 0) {
56
+ return { messages: [] };
57
+ }
58
+
59
+ const { messages, cursor } = await input.messageStore.query(
60
+ input.tenant,
61
+ filterResolution.projectedFilters,
62
+ input.messageSort,
63
+ input.pagination
64
+ );
65
+
66
+ return { messages: messages.filter(Records.isRecordsWrite), cursor };
67
+ }
68
+
69
+ /**
70
+ * Counts records with bounded `$recordLimit` occupancy projection when every limited filter targets one concrete scope.
71
+ */
72
+ export async function countRecordsWithRecordLimitOccupancy(input: Omit<RecordLimitOccupancyQueryInput, 'pagination'>): Promise<number> {
73
+ const filterResolution = await resolveRecordLimitFilters(input);
74
+ if (filterResolution === undefined) {
75
+ return input.messageStore.count(input.tenant, input.filters, input.messageSort);
76
+ }
77
+
78
+ if (filterResolution.projectedFilters.length === 0) {
79
+ return 0;
80
+ }
81
+
82
+ return input.messageStore.count(input.tenant, filterResolution.projectedFilters, input.messageSort);
83
+ }
84
+
85
+ /**
86
+ * Returns true when the latest RecordsWrite is visible under the `$recordLimit` projection.
87
+ */
88
+ export async function isRecordLimitOccupant(input: RecordLimitOccupancyDependencies & {
89
+ tenant: string;
90
+ message: RecordsWriteMessage;
91
+ messageTimestamp: string;
92
+ }): Promise<boolean> {
93
+ const recordLimit = await getRecordLimitForMessage({
94
+ messageStore : input.messageStore,
95
+ validationStateReader : input.validationStateReader,
96
+ tenant : input.tenant,
97
+ message : input.message,
98
+ messageTimestamp : input.messageTimestamp,
99
+ recordLimitDefinitions : new Map(),
100
+ });
101
+
102
+ if (recordLimit === undefined) {
103
+ return true;
104
+ }
105
+
106
+ const occupantRecordIds = await findOccupantRecordIds({
107
+ messageStore : input.messageStore,
108
+ tenant : input.tenant,
109
+ scope : getRecordLimitScope(input.message),
110
+ recordLimit,
111
+ });
112
+
113
+ return occupantRecordIds.has(input.message.recordId);
114
+ }
115
+
116
+ async function resolveRecordLimitFilters(
117
+ input: Omit<RecordLimitOccupancyQueryInput, 'pagination'>
118
+ ): Promise<RecordLimitFilterResolution | undefined> {
119
+ const recordLimitDefinitions = new Map<string, ProtocolRecordLimitDefinition | undefined>();
120
+ const projectedFilters: Filter[] = [];
121
+ let projectionApplied = false;
122
+
123
+ for (const filter of input.filters) {
124
+ const recordLimit = await getRecordLimitForFilter({
125
+ messageStore : input.messageStore,
126
+ validationStateReader : input.validationStateReader,
127
+ tenant : input.tenant,
128
+ filter,
129
+ messageTimestamp : input.messageTimestamp,
130
+ recordLimitDefinitions,
131
+ });
132
+
133
+ if (recordLimit === undefined) {
134
+ projectedFilters.push(filter);
135
+ continue;
136
+ }
137
+
138
+ const scope = getRecordLimitScopeFromFilter(filter);
139
+ if (scope === undefined) {
140
+ return undefined;
141
+ }
142
+
143
+ const occupantRecordIds = await findOccupantRecordIds({
144
+ messageStore : input.messageStore,
145
+ tenant : input.tenant,
146
+ scope,
147
+ recordLimit,
148
+ });
149
+
150
+ const projectedFilter = buildProjectedFilter(filter, occupantRecordIds);
151
+ if (projectedFilter !== undefined) {
152
+ projectedFilters.push(projectedFilter);
153
+ }
154
+ projectionApplied = true;
155
+ }
156
+
157
+ return projectionApplied ? { projectedFilters } : undefined;
158
+ }
159
+
160
+ async function getRecordLimitForMessage(input: RecordLimitOccupancyDependencies & {
161
+ tenant: string;
162
+ message: RecordsWriteMessage;
163
+ messageTimestamp: string;
164
+ recordLimitDefinitions: Map<string, ProtocolRecordLimitDefinition | undefined>;
165
+ }): Promise<ProtocolRecordLimitDefinition | undefined> {
166
+ const { protocol, protocolPath } = input.message.descriptor;
167
+ if (protocol === undefined || protocolPath === undefined) {
168
+ return undefined;
169
+ }
170
+
171
+ return getRecordLimit({
172
+ validationStateReader : input.validationStateReader,
173
+ tenant : input.tenant,
174
+ protocol,
175
+ protocolPath,
176
+ messageTimestamp : input.messageTimestamp,
177
+ recordLimitDefinitions : input.recordLimitDefinitions,
178
+ });
179
+ }
180
+
181
+ async function getRecordLimitForFilter(input: RecordLimitOccupancyDependencies & {
182
+ tenant: string;
183
+ filter: Filter;
184
+ messageTimestamp: string;
185
+ recordLimitDefinitions: Map<string, ProtocolRecordLimitDefinition | undefined>;
186
+ }): Promise<ProtocolRecordLimitDefinition | undefined> {
187
+ if (input.filter.interface !== DwnInterfaceName.Records ||
188
+ input.filter.method !== DwnMethodName.Write ||
189
+ input.filter.isLatestBaseState !== true
190
+ ) {
191
+ return undefined;
192
+ }
193
+
194
+ const { protocol, protocolPath } = input.filter;
195
+ if (typeof protocol !== 'string' || typeof protocolPath !== 'string') {
196
+ return undefined;
197
+ }
198
+
199
+ return getRecordLimit({
200
+ validationStateReader : input.validationStateReader,
201
+ tenant : input.tenant,
202
+ protocol,
203
+ protocolPath,
204
+ messageTimestamp : input.messageTimestamp,
205
+ recordLimitDefinitions : input.recordLimitDefinitions,
206
+ });
207
+ }
208
+
209
+ async function getRecordLimit(input: {
210
+ validationStateReader: ValidationStateReader;
211
+ tenant: string;
212
+ protocol: string;
213
+ protocolPath: string;
214
+ messageTimestamp: string;
215
+ recordLimitDefinitions: Map<string, ProtocolRecordLimitDefinition | undefined>;
216
+ }): Promise<ProtocolRecordLimitDefinition | undefined> {
217
+ const key = `${input.protocol}\u0000${input.protocolPath}`;
218
+ if (!input.recordLimitDefinitions.has(key)) {
219
+ let protocolDefinition;
220
+ try {
221
+ protocolDefinition = await input.validationStateReader.fetchProtocolDefinition(
222
+ input.tenant,
223
+ input.protocol,
224
+ input.messageTimestamp,
225
+ );
226
+ } catch (error) {
227
+ if (error instanceof DwnError && error.code === DwnErrorCode.ProtocolAuthorizationProtocolNotFound) {
228
+ input.recordLimitDefinitions.set(key, undefined);
229
+ return undefined;
230
+ }
231
+ throw error;
232
+ }
233
+
234
+ const ruleSet = getRuleSetAtPath(input.protocolPath, protocolDefinition.structure);
235
+ const recordLimit = ruleSet?.$recordLimit;
236
+ input.recordLimitDefinitions.set(
237
+ key,
238
+ recordLimit?.strategy === ProtocolRecordLimitStrategy.Reject ? recordLimit : undefined
239
+ );
240
+ }
241
+
242
+ return input.recordLimitDefinitions.get(key);
243
+ }
244
+
245
+ async function findOccupantRecordIds(input: {
246
+ messageStore: MessageStore;
247
+ tenant: string;
248
+ scope: RecordLimitScope;
249
+ recordLimit: ProtocolRecordLimitDefinition;
250
+ }): Promise<Set<string>> {
251
+ const scopeFilter = buildRecordLimitScopeFilter(input.scope);
252
+ const messageSort = { dateCreated: SortDirection.Ascending };
253
+ const { messages: firstPage } = await input.messageStore.query(
254
+ input.tenant,
255
+ [scopeFilter],
256
+ messageSort,
257
+ { limit: input.recordLimit.max }
258
+ );
259
+ const firstPageCandidates = firstPage.filter(Records.isRecordsWrite);
260
+ if (firstPageCandidates.length === 0) {
261
+ return new Set();
262
+ }
263
+
264
+ const boundaryDateCreated = firstPageCandidates.at(-1)!.descriptor.dateCreated;
265
+ const beforeBoundary = firstPageCandidates.filter(
266
+ (message): boolean => message.descriptor.dateCreated < boundaryDateCreated
267
+ );
268
+ let boundaryCandidates = firstPageCandidates.filter(
269
+ (message): boolean => message.descriptor.dateCreated === boundaryDateCreated
270
+ );
271
+
272
+ if (firstPageCandidates.length === input.recordLimit.max) {
273
+ const { messages } = await input.messageStore.query(
274
+ input.tenant,
275
+ [{ ...scopeFilter, dateCreated: boundaryDateCreated }],
276
+ messageSort
277
+ );
278
+ boundaryCandidates = messages.filter(Records.isRecordsWrite);
279
+ }
280
+
281
+ boundaryCandidates.sort(compareRecordLimitCandidates);
282
+
283
+ const rankedCandidates = [
284
+ ...beforeBoundary,
285
+ ...boundaryCandidates,
286
+ ];
287
+
288
+ return new Set(
289
+ rankedCandidates
290
+ .slice(0, input.recordLimit.max)
291
+ .map((message): string => message.recordId)
292
+ );
293
+ }
294
+
295
+ function buildRecordLimitScopeFilter(scope: RecordLimitScope): Filter {
296
+ const filter: Filter = {
297
+ interface : DwnInterfaceName.Records,
298
+ method : DwnMethodName.Write,
299
+ isLatestBaseState : true,
300
+ protocol : scope.protocol,
301
+ protocolPath : scope.protocolPath,
302
+ };
303
+
304
+ if (scope.parentContextId !== '') {
305
+ filter.contextId = FilterUtility.constructPrefixFilterAsRangeFilter(scope.parentContextId);
306
+ }
307
+
308
+ return filter;
309
+ }
310
+
311
+ function getRecordLimitScopeFromFilter(filter: Filter): RecordLimitScope | undefined {
312
+ const { protocol, protocolPath } = filter;
313
+ if (typeof protocol !== 'string' || typeof protocolPath !== 'string') {
314
+ return undefined;
315
+ }
316
+
317
+ if (!protocolPath.includes('/')) {
318
+ return { protocol, protocolPath, parentContextId: '' };
319
+ }
320
+
321
+ const parentContextId = getExactParentContextIdFromFilter(filter);
322
+ if (parentContextId === undefined) {
323
+ return undefined;
324
+ }
325
+
326
+ return { protocol, protocolPath, parentContextId };
327
+ }
328
+
329
+ function getRecordLimitScope(message: RecordsWriteMessage): RecordLimitScope {
330
+ return {
331
+ protocol : message.descriptor.protocol,
332
+ protocolPath : message.descriptor.protocolPath,
333
+ parentContextId : Records.getParentContextFromOfContextId(message.contextId) ?? '',
334
+ };
335
+ }
336
+
337
+ function getExactParentContextIdFromFilter(filter: Filter): string | undefined {
338
+ const { contextId } = filter;
339
+ if (contextId === undefined || !FilterUtility.isRangeFilter(contextId)) {
340
+ return undefined;
341
+ }
342
+
343
+ if (typeof contextId.gte !== 'string' || contextId.lt !== `${contextId.gte}\uffff`) {
344
+ return undefined;
345
+ }
346
+
347
+ return contextId.gte;
348
+ }
349
+
350
+ function buildProjectedFilter(filter: Filter, occupantRecordIds: Set<string>): Filter | undefined {
351
+ let projectedRecordIds = Array.from(occupantRecordIds);
352
+ const existingRecordIdFilter = filter.recordId;
353
+ if (typeof existingRecordIdFilter === 'string') {
354
+ projectedRecordIds = occupantRecordIds.has(existingRecordIdFilter) ? [existingRecordIdFilter] : [];
355
+ } else if (Array.isArray(existingRecordIdFilter)) {
356
+ projectedRecordIds = existingRecordIdFilter
357
+ .filter((recordId): recordId is string => typeof recordId === 'string' && occupantRecordIds.has(recordId));
358
+ }
359
+
360
+ if (projectedRecordIds.length === 0) {
361
+ return undefined;
362
+ }
363
+
364
+ return {
365
+ ...filter,
366
+ recordId: projectedRecordIds,
367
+ };
368
+ }
369
+
370
+ function compareRecordLimitCandidates(left: RecordsWriteMessage, right: RecordsWriteMessage): number {
371
+ const dateComparison = lexicographicalCompare(left.descriptor.dateCreated, right.descriptor.dateCreated);
372
+ if (dateComparison !== 0) {
373
+ return dateComparison;
374
+ }
375
+
376
+ return lexicographicalCompare(left.recordId, right.recordId);
377
+ }
@@ -36,6 +36,26 @@ export class Records {
36
36
  return isRecordsWrite;
37
37
  }
38
38
 
39
+ /**
40
+ * Gets the newest `RecordsWrite` from the given message set.
41
+ */
42
+ public static async getNewestRecordsWrite(messages: GenericMessage[]): Promise<RecordsWriteMessage | undefined> {
43
+ const recordsWriteMessages = messages.filter(Records.isRecordsWrite);
44
+ const newestRecordsWrite = await Message.getNewestMessage(recordsWriteMessages);
45
+ return newestRecordsWrite as RecordsWriteMessage | undefined;
46
+ }
47
+
48
+ /**
49
+ * Gets the newest `RecordsDelete` from the given message set.
50
+ */
51
+ public static async getNewestRecordsDelete(messages: GenericMessage[]): Promise<RecordsDeleteMessage | undefined> {
52
+ const recordsDeleteMessages = messages.filter((message): message is RecordsDeleteMessage =>
53
+ message.descriptor.interface === DwnInterfaceName.Records && message.descriptor.method === DwnMethodName.Delete
54
+ );
55
+ const newestRecordsDelete = await Message.getNewestMessage(recordsDeleteMessages);
56
+ return newestRecordsDelete as RecordsDeleteMessage | undefined;
57
+ }
58
+
39
59
  /**
40
60
  * Decrypts the encrypted data in a message reply.
41
61
  *
@@ -285,6 +305,35 @@ export class Records {
285
305
  return filterCopy;
286
306
  }
287
307
 
308
+ /**
309
+ * Nested protocol-path queries must pin one parent context. Otherwise the same
310
+ * protocol type is read across every parent instance.
311
+ */
312
+ public static validateNestedProtocolPathQueryScope(
313
+ filter: RecordsFilter,
314
+ errorCode: DwnErrorCode,
315
+ operationName: string,
316
+ ): void {
317
+ const { contextId, protocolPath } = filter;
318
+ if (!protocolPath?.includes('/')) {
319
+ return;
320
+ }
321
+
322
+ const expectedParentDepth = protocolPath.split('/').length - 1;
323
+ const contextIdSegments = contextId?.split('/');
324
+ if (
325
+ contextIdSegments?.length === expectedParentDepth &&
326
+ contextIdSegments.every(segment => segment.length > 0)
327
+ ) {
328
+ return;
329
+ }
330
+
331
+ throw new DwnError(
332
+ errorCode,
333
+ `${operationName} for nested protocol path '${protocolPath}' must include the direct parent contextId in the filter`
334
+ );
335
+ }
336
+
288
337
 
289
338
  public static isStartsWithFilter(filter: RecordsWriteTagsFilter): filter is StartsWithFilter {
290
339
  return typeof filter === 'object' && ('startsWith' in filter && typeof filter.startsWith === 'string');
@@ -530,25 +579,32 @@ export class Records {
530
579
  }
531
580
 
532
581
  /**
533
- * Checks if the given RecordsDelete message can be performed against a record with the given newest existing state.
582
+ * Checks whether the given `RecordsDelete` is beaten by an existing tombstone for the record,
583
+ * per the tombstone lattice. A tombstone displaces any `RecordsWrite` regardless of timestamp
584
+ * (delete-wins). Among competing tombstones one canonical winner stands on every replica:
585
+ * a prune beats a plain delete regardless of timestamp — the cascade is a side effect, and a
586
+ * plain-newer winner would leave replicas that ran the cascade diverged from those that never
587
+ * would — and within the same class the newest tombstone wins, with `Message.isNewer`'s
588
+ * (messageTimestamp, CID) total order picking the same winner everywhere. Admission and
589
+ * resumable-task replay must share this predicate: state can advance between acceptance and
590
+ * replay, and replay must never admit a delete that admission would now reject.
534
591
  */
535
- public static canPerformDeleteAgainstRecord(deleteToBePerformed: RecordsDeleteMessage, newestExistingMessage: GenericMessage | undefined): boolean {
536
- if (newestExistingMessage === undefined) {
592
+ public static async isDeleteBeatenByExistingTombstone(
593
+ deleteToBePerformed: RecordsDeleteMessage,
594
+ newestExistingMessage: GenericMessage
595
+ ): Promise<boolean> {
596
+ if (newestExistingMessage.descriptor.method !== DwnMethodName.Delete) {
537
597
  return false;
538
598
  }
539
599
 
540
- // can't perform delete if:
541
- // attempting to delete on an already deleted record; or
542
- // attempting to prune on an already pruned record;
543
- if (newestExistingMessage.descriptor.method === DwnMethodName.Delete) {
544
- if (deleteToBePerformed.descriptor.prune !== true) {
545
- return false;
546
- } else if ((newestExistingMessage as RecordsDeleteMessage).descriptor.prune === true) {
547
- return false;
548
- }
600
+ const incomingIsPrune = deleteToBePerformed.descriptor.prune === true;
601
+ const existingIsPrune = (newestExistingMessage as RecordsDeleteMessage).descriptor.prune === true;
602
+ if (incomingIsPrune !== existingIsPrune) {
603
+ return existingIsPrune;
549
604
  }
550
605
 
551
- return true;
606
+ const incomingDeleteIsNewest = await Message.isNewer(deleteToBePerformed, newestExistingMessage);
607
+ return !incomingDeleteIsNewest;
552
608
  }
553
609
 
554
610
  /**