@enbox/dwn-sdk-js 0.4.0 → 0.4.2

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 (522) hide show
  1. package/README.md +4 -4
  2. package/dist/browser.mjs +3 -10
  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 +34 -89
  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 +12 -9
  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/protocol-tags.js +262 -0
  99. package/dist/esm/src/utils/protocol-tags.js.map +1 -0
  100. package/dist/esm/src/utils/record-limit-occupancy.js +244 -0
  101. package/dist/esm/src/utils/record-limit-occupancy.js.map +1 -0
  102. package/dist/esm/src/utils/records.js +50 -14
  103. package/dist/esm/src/utils/records.js.map +1 -1
  104. package/dist/esm/src/utils/replication.js +85 -0
  105. package/dist/esm/src/utils/replication.js.map +1 -0
  106. package/dist/esm/tests/core/grant-authorization.spec.js +4 -4
  107. package/dist/esm/tests/core/grant-authorization.spec.js.map +1 -1
  108. package/dist/esm/tests/core/process-message-parity.spec.js +222 -0
  109. package/dist/esm/tests/core/process-message-parity.spec.js.map +1 -0
  110. package/dist/esm/tests/core/protocol-authorization.spec.js +5 -2
  111. package/dist/esm/tests/core/protocol-authorization.spec.js.map +1 -1
  112. package/dist/esm/tests/core/records-grant-authorization.spec.js +5 -5
  113. package/dist/esm/tests/core/records-grant-authorization.spec.js.map +1 -1
  114. package/dist/esm/tests/core/replication-apply.spec.js +55 -1
  115. package/dist/esm/tests/core/replication-apply.spec.js.map +1 -1
  116. package/dist/esm/tests/core/replication-replay-property.spec.js +350 -0
  117. package/dist/esm/tests/core/replication-replay-property.spec.js.map +1 -0
  118. package/dist/esm/tests/core/validation-read-closure.spec.js +469 -0
  119. package/dist/esm/tests/core/validation-read-closure.spec.js.map +1 -0
  120. package/dist/esm/tests/core/validation-state-reader.spec.js +716 -0
  121. package/dist/esm/tests/core/validation-state-reader.spec.js.map +1 -0
  122. package/dist/esm/tests/durable-event-log.spec.js +373 -0
  123. package/dist/esm/tests/durable-event-log.spec.js.map +1 -0
  124. package/dist/esm/tests/dwn.spec.js +504 -35
  125. package/dist/esm/tests/dwn.spec.js.map +1 -1
  126. package/dist/esm/tests/features/author-delegated-grant.spec.js +9 -6
  127. package/dist/esm/tests/features/author-delegated-grant.spec.js.map +1 -1
  128. package/dist/esm/tests/features/owner-delegated-grant.spec.js +1 -4
  129. package/dist/esm/tests/features/owner-delegated-grant.spec.js.map +1 -1
  130. package/dist/esm/tests/features/owner-signature.spec.js +1 -4
  131. package/dist/esm/tests/features/owner-signature.spec.js.map +1 -1
  132. package/dist/esm/tests/features/permissions.spec.js +165 -4
  133. package/dist/esm/tests/features/permissions.spec.js.map +1 -1
  134. package/dist/esm/tests/features/protocol-composition.spec.js +8 -11
  135. package/dist/esm/tests/features/protocol-composition.spec.js.map +1 -1
  136. package/dist/esm/tests/features/protocol-create-action.spec.js +1 -4
  137. package/dist/esm/tests/features/protocol-create-action.spec.js.map +1 -1
  138. package/dist/esm/tests/features/protocol-delete-action.spec.js +3 -5
  139. package/dist/esm/tests/features/protocol-delete-action.spec.js.map +1 -1
  140. package/dist/esm/tests/features/protocol-update-action.spec.js +3 -6
  141. package/dist/esm/tests/features/protocol-update-action.spec.js.map +1 -1
  142. package/dist/esm/tests/features/records-delivery.spec.js +1 -4
  143. package/dist/esm/tests/features/records-delivery.spec.js.map +1 -1
  144. package/dist/esm/tests/features/records-immutable.spec.js +1 -4
  145. package/dist/esm/tests/features/records-immutable.spec.js.map +1 -1
  146. package/dist/esm/tests/features/records-nested-query-scope.spec.js +281 -0
  147. package/dist/esm/tests/features/records-nested-query-scope.spec.js.map +1 -0
  148. package/dist/esm/tests/features/records-prune-cross-protocol.spec.js +3 -7
  149. package/dist/esm/tests/features/records-prune-cross-protocol.spec.js.map +1 -1
  150. package/dist/esm/tests/features/records-prune.spec.js +11 -22
  151. package/dist/esm/tests/features/records-prune.spec.js.map +1 -1
  152. package/dist/esm/tests/features/records-record-limit.spec.js +441 -231
  153. package/dist/esm/tests/features/records-record-limit.spec.js.map +1 -1
  154. package/dist/esm/tests/features/records-squash.spec.js +6 -4
  155. package/dist/esm/tests/features/records-squash.spec.js.map +1 -1
  156. package/dist/esm/tests/features/records-tags.spec.js +1 -4
  157. package/dist/esm/tests/features/records-tags.spec.js.map +1 -1
  158. package/dist/esm/tests/features/resumable-tasks.spec.js +3 -5
  159. package/dist/esm/tests/features/resumable-tasks.spec.js.map +1 -1
  160. package/dist/esm/tests/fuzz/message-store.fuzz.spec.js +1 -2
  161. package/dist/esm/tests/fuzz/message-store.fuzz.spec.js.map +1 -1
  162. package/dist/esm/tests/fuzz/process-message.fuzz.spec.js +2 -4
  163. package/dist/esm/tests/fuzz/process-message.fuzz.spec.js.map +1 -1
  164. package/dist/esm/tests/fuzz/schema-validation.fuzz.spec.js +1 -1
  165. package/dist/esm/tests/fuzz/schema-validation.fuzz.spec.js.map +1 -1
  166. package/dist/esm/tests/handlers/messages-query.spec.js +246 -0
  167. package/dist/esm/tests/handlers/messages-query.spec.js.map +1 -0
  168. package/dist/esm/tests/handlers/messages-read.spec.js +2 -5
  169. package/dist/esm/tests/handlers/messages-read.spec.js.map +1 -1
  170. package/dist/esm/tests/handlers/messages-subscribe.spec.js +3 -14
  171. package/dist/esm/tests/handlers/messages-subscribe.spec.js.map +1 -1
  172. package/dist/esm/tests/handlers/protocols-configure.spec.js +27 -26
  173. package/dist/esm/tests/handlers/protocols-configure.spec.js.map +1 -1
  174. package/dist/esm/tests/handlers/protocols-query.spec.js +1 -4
  175. package/dist/esm/tests/handlers/protocols-query.spec.js.map +1 -1
  176. package/dist/esm/tests/handlers/records-count.spec.js +1 -4
  177. package/dist/esm/tests/handlers/records-count.spec.js.map +1 -1
  178. package/dist/esm/tests/handlers/records-delete.spec.js +312 -30
  179. package/dist/esm/tests/handlers/records-delete.spec.js.map +1 -1
  180. package/dist/esm/tests/handlers/records-query.spec.js +32 -9
  181. package/dist/esm/tests/handlers/records-query.spec.js.map +1 -1
  182. package/dist/esm/tests/handlers/records-read.spec.js +4 -4
  183. package/dist/esm/tests/handlers/records-read.spec.js.map +1 -1
  184. package/dist/esm/tests/handlers/records-subscribe.spec.js +33 -14
  185. package/dist/esm/tests/handlers/records-subscribe.spec.js.map +1 -1
  186. package/dist/esm/tests/handlers/records-write.spec.js +82 -36
  187. package/dist/esm/tests/handlers/records-write.spec.js.map +1 -1
  188. package/dist/esm/tests/interfaces/records-delete.spec.js +69 -2
  189. package/dist/esm/tests/interfaces/records-delete.spec.js.map +1 -1
  190. package/dist/esm/tests/interfaces/records-write.spec.js +4 -3
  191. package/dist/esm/tests/interfaces/records-write.spec.js.map +1 -1
  192. package/dist/esm/tests/protocols/permissions.spec.js +55 -6
  193. package/dist/esm/tests/protocols/permissions.spec.js.map +1 -1
  194. package/dist/esm/tests/scenarios/aggregator.spec.js +1 -4
  195. package/dist/esm/tests/scenarios/aggregator.spec.js.map +1 -1
  196. package/dist/esm/tests/scenarios/deleted-record.spec.js +1 -4
  197. package/dist/esm/tests/scenarios/deleted-record.spec.js.map +1 -1
  198. package/dist/esm/tests/scenarios/end-to-end-tests.spec.js +1 -4
  199. package/dist/esm/tests/scenarios/end-to-end-tests.spec.js.map +1 -1
  200. package/dist/esm/tests/scenarios/nested-roles.spec.js +1 -4
  201. package/dist/esm/tests/scenarios/nested-roles.spec.js.map +1 -1
  202. package/dist/esm/tests/scenarios/subscriptions.spec.js +1 -4
  203. package/dist/esm/tests/scenarios/subscriptions.spec.js.map +1 -1
  204. package/dist/esm/tests/store/message-store-level.spec.js +361 -5
  205. package/dist/esm/tests/store/message-store-level.spec.js.map +1 -1
  206. package/dist/esm/tests/store/message-store.spec.js +60 -0
  207. package/dist/esm/tests/store/message-store.spec.js.map +1 -1
  208. package/dist/esm/tests/test-event-stream.js +7 -3
  209. package/dist/esm/tests/test-event-stream.js.map +1 -1
  210. package/dist/esm/tests/test-stores.js +19 -9
  211. package/dist/esm/tests/test-stores.js.map +1 -1
  212. package/dist/esm/tests/test-suite.js +4 -2
  213. package/dist/esm/tests/test-suite.js.map +1 -1
  214. package/dist/esm/tests/utils/protocol-tags.spec.js +96 -0
  215. package/dist/esm/tests/utils/protocol-tags.spec.js.map +1 -0
  216. package/dist/esm/tests/utils/test-data-generator.js +25 -0
  217. package/dist/esm/tests/utils/test-data-generator.js.map +1 -1
  218. package/dist/esm/tests/utils/test-stub-generator.js.map +1 -1
  219. package/dist/esm/tests/utils/test-validation-state-reader.js +16 -0
  220. package/dist/esm/tests/utils/test-validation-state-reader.js.map +1 -0
  221. package/dist/types/generated/precompiled-validators.d.ts +6 -6
  222. package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
  223. package/dist/types/src/core/core-protocol.d.ts +3 -3
  224. package/dist/types/src/core/core-protocol.d.ts.map +1 -1
  225. package/dist/types/src/core/dwn-constant.d.ts +5 -0
  226. package/dist/types/src/core/dwn-constant.d.ts.map +1 -1
  227. package/dist/types/src/core/dwn-error.d.ts +12 -4
  228. package/dist/types/src/core/dwn-error.d.ts.map +1 -1
  229. package/dist/types/src/core/grant-authorization.d.ts +5 -5
  230. package/dist/types/src/core/grant-authorization.d.ts.map +1 -1
  231. package/dist/types/src/core/message-reply.d.ts +5 -4
  232. package/dist/types/src/core/message-reply.d.ts.map +1 -1
  233. package/dist/types/src/core/messages-grant-authorization.d.ts +12 -14
  234. package/dist/types/src/core/messages-grant-authorization.d.ts.map +1 -1
  235. package/dist/types/src/core/protocol-authorization-action.d.ts +4 -5
  236. package/dist/types/src/core/protocol-authorization-action.d.ts.map +1 -1
  237. package/dist/types/src/core/protocol-authorization-validation.d.ts +14 -17
  238. package/dist/types/src/core/protocol-authorization-validation.d.ts.map +1 -1
  239. package/dist/types/src/core/protocol-authorization.d.ts +8 -33
  240. package/dist/types/src/core/protocol-authorization.d.ts.map +1 -1
  241. package/dist/types/src/core/protocols-grant-authorization.d.ts +4 -4
  242. package/dist/types/src/core/protocols-grant-authorization.d.ts.map +1 -1
  243. package/dist/types/src/core/recording-validation-state-reader.d.ts +75 -0
  244. package/dist/types/src/core/recording-validation-state-reader.d.ts.map +1 -0
  245. package/dist/types/src/core/records-grant-authorization.d.ts +8 -8
  246. package/dist/types/src/core/records-grant-authorization.d.ts.map +1 -1
  247. package/dist/types/src/core/replication-apply.d.ts +36 -0
  248. package/dist/types/src/core/replication-apply.d.ts.map +1 -1
  249. package/dist/types/src/core/resumable-task-manager.d.ts +1 -1
  250. package/dist/types/src/core/resumable-task-manager.d.ts.map +1 -1
  251. package/dist/types/src/core/validation-state-reader.d.ts +79 -0
  252. package/dist/types/src/core/validation-state-reader.d.ts.map +1 -0
  253. package/dist/types/src/dwn.d.ts +33 -20
  254. package/dist/types/src/dwn.d.ts.map +1 -1
  255. package/dist/types/src/enums/dwn-interface-method.d.ts +0 -1
  256. package/dist/types/src/enums/dwn-interface-method.d.ts.map +1 -1
  257. package/dist/types/src/event-stream/durable-event-log.d.ts +69 -0
  258. package/dist/types/src/event-stream/durable-event-log.d.ts.map +1 -0
  259. package/dist/types/src/event-stream/event-emitter-wake-publisher.d.ts +13 -0
  260. package/dist/types/src/event-stream/event-emitter-wake-publisher.d.ts.map +1 -0
  261. package/dist/types/src/handlers/messages-query.d.ts +20 -0
  262. package/dist/types/src/handlers/messages-query.d.ts.map +1 -0
  263. package/dist/types/src/handlers/messages-read.d.ts +1 -1
  264. package/dist/types/src/handlers/messages-read.d.ts.map +1 -1
  265. package/dist/types/src/handlers/messages-subscribe.d.ts.map +1 -1
  266. package/dist/types/src/handlers/protocols-configure.d.ts +0 -5
  267. package/dist/types/src/handlers/protocols-configure.d.ts.map +1 -1
  268. package/dist/types/src/handlers/records-count.d.ts +2 -1
  269. package/dist/types/src/handlers/records-count.d.ts.map +1 -1
  270. package/dist/types/src/handlers/records-delete.d.ts +2 -2
  271. package/dist/types/src/handlers/records-delete.d.ts.map +1 -1
  272. package/dist/types/src/handlers/records-query.d.ts +1 -1
  273. package/dist/types/src/handlers/records-query.d.ts.map +1 -1
  274. package/dist/types/src/handlers/records-read.d.ts +2 -1
  275. package/dist/types/src/handlers/records-read.d.ts.map +1 -1
  276. package/dist/types/src/handlers/records-subscribe.d.ts +4 -5
  277. package/dist/types/src/handlers/records-subscribe.d.ts.map +1 -1
  278. package/dist/types/src/handlers/records-write.d.ts +3 -11
  279. package/dist/types/src/handlers/records-write.d.ts.map +1 -1
  280. package/dist/types/src/index.d.ts +14 -16
  281. package/dist/types/src/index.d.ts.map +1 -1
  282. package/dist/types/src/interfaces/messages-query.d.ts +23 -0
  283. package/dist/types/src/interfaces/messages-query.d.ts.map +1 -0
  284. package/dist/types/src/interfaces/protocols-configure.d.ts +3 -3
  285. package/dist/types/src/interfaces/protocols-configure.d.ts.map +1 -1
  286. package/dist/types/src/interfaces/protocols-query.d.ts +2 -2
  287. package/dist/types/src/interfaces/protocols-query.d.ts.map +1 -1
  288. package/dist/types/src/interfaces/records-count.d.ts +3 -3
  289. package/dist/types/src/interfaces/records-count.d.ts.map +1 -1
  290. package/dist/types/src/interfaces/records-delete.d.ts +11 -3
  291. package/dist/types/src/interfaces/records-delete.d.ts.map +1 -1
  292. package/dist/types/src/interfaces/records-query.d.ts +3 -3
  293. package/dist/types/src/interfaces/records-query.d.ts.map +1 -1
  294. package/dist/types/src/interfaces/records-read.d.ts +3 -3
  295. package/dist/types/src/interfaces/records-read.d.ts.map +1 -1
  296. package/dist/types/src/interfaces/records-subscribe.d.ts +3 -3
  297. package/dist/types/src/interfaces/records-subscribe.d.ts.map +1 -1
  298. package/dist/types/src/interfaces/records-write.d.ts +15 -7
  299. package/dist/types/src/interfaces/records-write.d.ts.map +1 -1
  300. package/dist/types/src/protocols/permissions.d.ts +9 -12
  301. package/dist/types/src/protocols/permissions.d.ts.map +1 -1
  302. package/dist/types/src/store/index-level.d.ts +10 -1
  303. package/dist/types/src/store/index-level.d.ts.map +1 -1
  304. package/dist/types/src/store/level-wrapper.d.ts +5 -0
  305. package/dist/types/src/store/level-wrapper.d.ts.map +1 -1
  306. package/dist/types/src/store/message-store-level.d.ts +94 -14
  307. package/dist/types/src/store/message-store-level.d.ts.map +1 -1
  308. package/dist/types/src/store/storage-controller.d.ts +17 -14
  309. package/dist/types/src/store/storage-controller.d.ts.map +1 -1
  310. package/dist/types/src/types/message-store.d.ts +29 -1
  311. package/dist/types/src/types/message-store.d.ts.map +1 -1
  312. package/dist/types/src/types/message-types.d.ts +2 -0
  313. package/dist/types/src/types/message-types.d.ts.map +1 -1
  314. package/dist/types/src/types/messages-types.d.ts +21 -37
  315. package/dist/types/src/types/messages-types.d.ts.map +1 -1
  316. package/dist/types/src/types/method-handler.d.ts +2 -2
  317. package/dist/types/src/types/method-handler.d.ts.map +1 -1
  318. package/dist/types/src/types/permission-types.d.ts +1 -1
  319. package/dist/types/src/types/subscriptions.d.ts +50 -39
  320. package/dist/types/src/types/subscriptions.d.ts.map +1 -1
  321. package/dist/types/src/types/validation-state-reader.d.ts +116 -0
  322. package/dist/types/src/types/validation-state-reader.d.ts.map +1 -0
  323. package/dist/types/src/utils/messages.d.ts +10 -0
  324. package/dist/types/src/utils/messages.d.ts.map +1 -1
  325. package/dist/types/src/utils/protocol-tags.d.ts +15 -0
  326. package/dist/types/src/utils/protocol-tags.d.ts.map +1 -0
  327. package/dist/types/src/utils/record-limit-occupancy.d.ts +40 -0
  328. package/dist/types/src/utils/record-limit-occupancy.d.ts.map +1 -0
  329. package/dist/types/src/utils/records.d.ts +25 -3
  330. package/dist/types/src/utils/records.d.ts.map +1 -1
  331. package/dist/types/src/utils/replication.d.ts +22 -0
  332. package/dist/types/src/utils/replication.d.ts.map +1 -0
  333. package/dist/types/tests/core/process-message-parity.spec.d.ts +2 -0
  334. package/dist/types/tests/core/process-message-parity.spec.d.ts.map +1 -0
  335. package/dist/types/tests/core/replication-replay-property.spec.d.ts +2 -0
  336. package/dist/types/tests/core/replication-replay-property.spec.d.ts.map +1 -0
  337. package/dist/types/tests/core/validation-read-closure.spec.d.ts +2 -0
  338. package/dist/types/tests/core/validation-read-closure.spec.d.ts.map +1 -0
  339. package/dist/types/tests/core/validation-state-reader.spec.d.ts +2 -0
  340. package/dist/types/tests/core/validation-state-reader.spec.d.ts.map +1 -0
  341. package/dist/types/tests/durable-event-log.spec.d.ts +2 -0
  342. package/dist/types/tests/durable-event-log.spec.d.ts.map +1 -0
  343. package/dist/types/tests/dwn.spec.d.ts.map +1 -1
  344. package/dist/types/tests/features/author-delegated-grant.spec.d.ts.map +1 -1
  345. package/dist/types/tests/features/owner-delegated-grant.spec.d.ts.map +1 -1
  346. package/dist/types/tests/features/owner-signature.spec.d.ts.map +1 -1
  347. package/dist/types/tests/features/permissions.spec.d.ts.map +1 -1
  348. package/dist/types/tests/features/protocol-composition.spec.d.ts.map +1 -1
  349. package/dist/types/tests/features/protocol-create-action.spec.d.ts.map +1 -1
  350. package/dist/types/tests/features/protocol-delete-action.spec.d.ts.map +1 -1
  351. package/dist/types/tests/features/protocol-update-action.spec.d.ts.map +1 -1
  352. package/dist/types/tests/features/records-delivery.spec.d.ts.map +1 -1
  353. package/dist/types/tests/features/records-immutable.spec.d.ts.map +1 -1
  354. package/dist/types/tests/features/records-nested-query-scope.spec.d.ts +2 -0
  355. package/dist/types/tests/features/records-nested-query-scope.spec.d.ts.map +1 -0
  356. package/dist/types/tests/features/records-prune-cross-protocol.spec.d.ts.map +1 -1
  357. package/dist/types/tests/features/records-prune.spec.d.ts.map +1 -1
  358. package/dist/types/tests/features/records-record-limit.spec.d.ts.map +1 -1
  359. package/dist/types/tests/features/records-squash.spec.d.ts.map +1 -1
  360. package/dist/types/tests/features/records-tags.spec.d.ts.map +1 -1
  361. package/dist/types/tests/features/resumable-tasks.spec.d.ts.map +1 -1
  362. package/dist/types/tests/handlers/messages-query.spec.d.ts +2 -0
  363. package/dist/types/tests/handlers/messages-query.spec.d.ts.map +1 -0
  364. package/dist/types/tests/handlers/messages-read.spec.d.ts.map +1 -1
  365. package/dist/types/tests/handlers/messages-subscribe.spec.d.ts.map +1 -1
  366. package/dist/types/tests/handlers/protocols-configure.spec.d.ts.map +1 -1
  367. package/dist/types/tests/handlers/protocols-query.spec.d.ts.map +1 -1
  368. package/dist/types/tests/handlers/records-count.spec.d.ts.map +1 -1
  369. package/dist/types/tests/handlers/records-delete.spec.d.ts.map +1 -1
  370. package/dist/types/tests/handlers/records-query.spec.d.ts.map +1 -1
  371. package/dist/types/tests/handlers/records-read.spec.d.ts.map +1 -1
  372. package/dist/types/tests/handlers/records-subscribe.spec.d.ts.map +1 -1
  373. package/dist/types/tests/handlers/records-write.spec.d.ts.map +1 -1
  374. package/dist/types/tests/scenarios/deleted-record.spec.d.ts.map +1 -1
  375. package/dist/types/tests/scenarios/end-to-end-tests.spec.d.ts.map +1 -1
  376. package/dist/types/tests/scenarios/nested-roles.spec.d.ts.map +1 -1
  377. package/dist/types/tests/scenarios/subscriptions.spec.d.ts.map +1 -1
  378. package/dist/types/tests/store/message-store.spec.d.ts.map +1 -1
  379. package/dist/types/tests/test-event-stream.d.ts +1 -1
  380. package/dist/types/tests/test-event-stream.d.ts.map +1 -1
  381. package/dist/types/tests/test-stores.d.ts +5 -4
  382. package/dist/types/tests/test-stores.d.ts.map +1 -1
  383. package/dist/types/tests/test-suite.d.ts +1 -2
  384. package/dist/types/tests/test-suite.d.ts.map +1 -1
  385. package/dist/types/tests/utils/protocol-tags.spec.d.ts +2 -0
  386. package/dist/types/tests/utils/protocol-tags.spec.d.ts.map +1 -0
  387. package/dist/types/tests/utils/test-data-generator.d.ts +20 -1
  388. package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -1
  389. package/dist/types/tests/utils/test-validation-state-reader.d.ts +15 -0
  390. package/dist/types/tests/utils/test-validation-state-reader.d.ts.map +1 -0
  391. package/package.json +2 -2
  392. package/src/core/core-protocol.ts +3 -3
  393. package/src/core/dwn-constant.ts +7 -1
  394. package/src/core/dwn-error.ts +12 -4
  395. package/src/core/grant-authorization.ts +11 -20
  396. package/src/core/message-reply.ts +6 -5
  397. package/src/core/messages-grant-authorization.ts +37 -70
  398. package/src/core/protocol-authorization-action.ts +29 -38
  399. package/src/core/protocol-authorization-validation.ts +47 -121
  400. package/src/core/protocol-authorization.ts +56 -202
  401. package/src/core/protocols-grant-authorization.ts +9 -9
  402. package/src/core/recording-validation-state-reader.ts +130 -0
  403. package/src/core/records-grant-authorization.ts +16 -16
  404. package/src/core/replication-apply.ts +172 -32
  405. package/src/core/resumable-task-manager.ts +10 -8
  406. package/src/core/validation-state-reader.ts +350 -0
  407. package/src/dwn.ts +285 -192
  408. package/src/enums/dwn-interface-method.ts +0 -1
  409. package/src/event-stream/durable-event-log.ts +509 -0
  410. package/src/event-stream/event-emitter-wake-publisher.ts +34 -0
  411. package/src/handlers/messages-query.ts +203 -0
  412. package/src/handlers/messages-read.ts +9 -10
  413. package/src/handlers/messages-subscribe.ts +12 -13
  414. package/src/handlers/protocols-configure.ts +37 -58
  415. package/src/handlers/protocols-query.ts +1 -1
  416. package/src/handlers/records-count.ts +24 -17
  417. package/src/handlers/records-delete.ts +29 -27
  418. package/src/handlers/records-query.ts +38 -17
  419. package/src/handlers/records-read.ts +63 -50
  420. package/src/handlers/records-subscribe.ts +132 -19
  421. package/src/handlers/records-write.ts +77 -168
  422. package/src/index.ts +14 -17
  423. package/src/interfaces/messages-query.ts +70 -0
  424. package/src/interfaces/protocols-configure.ts +20 -10
  425. package/src/interfaces/protocols-query.ts +4 -5
  426. package/src/interfaces/records-count.ts +9 -4
  427. package/src/interfaces/records-delete.ts +25 -5
  428. package/src/interfaces/records-query.ts +9 -4
  429. package/src/interfaces/records-read.ts +4 -4
  430. package/src/interfaces/records-subscribe.ts +9 -4
  431. package/src/interfaces/records-write.ts +41 -13
  432. package/src/protocols/permissions.ts +32 -52
  433. package/src/store/index-level.ts +30 -9
  434. package/src/store/level-wrapper.ts +9 -1
  435. package/src/store/message-store-level.ts +757 -47
  436. package/src/store/storage-controller.ts +74 -63
  437. package/src/types/message-store.ts +45 -2
  438. package/src/types/message-types.ts +3 -1
  439. package/src/types/messages-types.ts +26 -45
  440. package/src/types/method-handler.ts +3 -3
  441. package/src/types/permission-types.ts +1 -1
  442. package/src/types/subscriptions.ts +53 -42
  443. package/src/types/validation-state-reader.ts +127 -0
  444. package/src/utils/messages.ts +25 -1
  445. package/src/utils/protocol-tags.ts +366 -0
  446. package/src/utils/record-limit-occupancy.ts +377 -0
  447. package/src/utils/records.ts +69 -13
  448. package/src/utils/replication.ts +122 -0
  449. package/dist/esm/src/core/record-chain.js +0 -64
  450. package/dist/esm/src/core/record-chain.js.map +0 -1
  451. package/dist/esm/src/event-stream/event-emitter-event-log.js +0 -334
  452. package/dist/esm/src/event-stream/event-emitter-event-log.js.map +0 -1
  453. package/dist/esm/src/handlers/messages-sync.js +0 -278
  454. package/dist/esm/src/handlers/messages-sync.js.map +0 -1
  455. package/dist/esm/src/interfaces/messages-sync.js.map +0 -1
  456. package/dist/esm/src/smt/smt-store-level.js +0 -103
  457. package/dist/esm/src/smt/smt-store-level.js.map +0 -1
  458. package/dist/esm/src/smt/smt-store-memory.js +0 -41
  459. package/dist/esm/src/smt/smt-store-memory.js.map +0 -1
  460. package/dist/esm/src/smt/smt-utils.js +0 -129
  461. package/dist/esm/src/smt/smt-utils.js.map +0 -1
  462. package/dist/esm/src/smt/sparse-merkle-tree.js +0 -577
  463. package/dist/esm/src/smt/sparse-merkle-tree.js.map +0 -1
  464. package/dist/esm/src/state-index/state-index-level.js +0 -191
  465. package/dist/esm/src/state-index/state-index-level.js.map +0 -1
  466. package/dist/esm/src/types/smt-types.js +0 -5
  467. package/dist/esm/src/types/smt-types.js.map +0 -1
  468. package/dist/esm/src/types/state-index.js +0 -2
  469. package/dist/esm/src/types/state-index.js.map +0 -1
  470. package/dist/esm/tests/event-emitter-event-log.spec.js +0 -499
  471. package/dist/esm/tests/event-emitter-event-log.spec.js.map +0 -1
  472. package/dist/esm/tests/handlers/messages-sync.spec.js +0 -1088
  473. package/dist/esm/tests/handlers/messages-sync.spec.js.map +0 -1
  474. package/dist/esm/tests/smt/smt-store-level.spec.js +0 -132
  475. package/dist/esm/tests/smt/smt-store-level.spec.js.map +0 -1
  476. package/dist/esm/tests/smt/sparse-merkle-tree.spec.js +0 -732
  477. package/dist/esm/tests/smt/sparse-merkle-tree.spec.js.map +0 -1
  478. package/dist/esm/tests/state-index/state-index-level.spec.js +0 -245
  479. package/dist/esm/tests/state-index/state-index-level.spec.js.map +0 -1
  480. package/dist/types/src/core/record-chain.d.ts +0 -24
  481. package/dist/types/src/core/record-chain.d.ts.map +0 -1
  482. package/dist/types/src/event-stream/event-emitter-event-log.d.ts +0 -80
  483. package/dist/types/src/event-stream/event-emitter-event-log.d.ts.map +0 -1
  484. package/dist/types/src/handlers/messages-sync.d.ts +0 -39
  485. package/dist/types/src/handlers/messages-sync.d.ts.map +0 -1
  486. package/dist/types/src/interfaces/messages-sync.d.ts +0 -20
  487. package/dist/types/src/interfaces/messages-sync.d.ts.map +0 -1
  488. package/dist/types/src/smt/smt-store-level.d.ts +0 -32
  489. package/dist/types/src/smt/smt-store-level.d.ts.map +0 -1
  490. package/dist/types/src/smt/smt-store-memory.d.ts +0 -22
  491. package/dist/types/src/smt/smt-store-memory.d.ts.map +0 -1
  492. package/dist/types/src/smt/smt-utils.d.ts +0 -58
  493. package/dist/types/src/smt/smt-utils.d.ts.map +0 -1
  494. package/dist/types/src/smt/sparse-merkle-tree.d.ts +0 -124
  495. package/dist/types/src/smt/sparse-merkle-tree.d.ts.map +0 -1
  496. package/dist/types/src/state-index/state-index-level.d.ts +0 -83
  497. package/dist/types/src/state-index/state-index-level.d.ts.map +0 -1
  498. package/dist/types/src/types/smt-types.d.ts +0 -81
  499. package/dist/types/src/types/smt-types.d.ts.map +0 -1
  500. package/dist/types/src/types/state-index.d.ts +0 -90
  501. package/dist/types/src/types/state-index.d.ts.map +0 -1
  502. package/dist/types/tests/event-emitter-event-log.spec.d.ts +0 -2
  503. package/dist/types/tests/event-emitter-event-log.spec.d.ts.map +0 -1
  504. package/dist/types/tests/handlers/messages-sync.spec.d.ts +0 -2
  505. package/dist/types/tests/handlers/messages-sync.spec.d.ts.map +0 -1
  506. package/dist/types/tests/smt/smt-store-level.spec.d.ts +0 -2
  507. package/dist/types/tests/smt/smt-store-level.spec.d.ts.map +0 -1
  508. package/dist/types/tests/smt/sparse-merkle-tree.spec.d.ts +0 -2
  509. package/dist/types/tests/smt/sparse-merkle-tree.spec.d.ts.map +0 -1
  510. package/dist/types/tests/state-index/state-index-level.spec.d.ts +0 -2
  511. package/dist/types/tests/state-index/state-index-level.spec.d.ts.map +0 -1
  512. package/src/core/record-chain.ts +0 -99
  513. package/src/event-stream/event-emitter-event-log.ts +0 -430
  514. package/src/handlers/messages-sync.ts +0 -403
  515. package/src/interfaces/messages-sync.ts +0 -69
  516. package/src/smt/smt-store-level.ts +0 -143
  517. package/src/smt/smt-store-memory.ts +0 -53
  518. package/src/smt/smt-utils.ts +0 -149
  519. package/src/smt/sparse-merkle-tree.ts +0 -698
  520. package/src/state-index/state-index-level.ts +0 -239
  521. package/src/types/smt-types.ts +0 -95
  522. package/src/types/state-index.ts +0 -100
@@ -1,10 +1,11 @@
1
1
  import sinon from 'sinon';
2
+ import nestedProtocol from './vectors/protocol-definitions/nested.json' with { type: 'json' };
2
3
  import { Dwn } from '../src/dwn.js';
3
- import { TestDataGenerator } from './utils/test-data-generator.js';
4
4
  import { TestEventLog } from './test-event-stream.js';
5
5
  import { TestStores } from './test-stores.js';
6
6
  import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'bun:test';
7
- import { DataStoreLevel, EventEmitterEventLog, Message, MessageStoreLevel, ResumableTaskStoreLevel, StateIndexLevel } from '../src/index.js';
7
+ import { DataStoreLevel, DataStream, DwnErrorCode, DwnMethodName, Jws, Message, MessageStoreLevel, RecordsDelete, RecordsRead, RecordsWrite, ResumableTaskStoreLevel, Time } from '../src/index.js';
8
+ import { defaultTestProtocolDefinition, TestDataGenerator } from './utils/test-data-generator.js';
8
9
  import { DidKey, UniversalResolver } from '@enbox/dids';
9
10
  export function testDwnClass() {
10
11
  describe('DWN', () => {
@@ -12,7 +13,6 @@ export function testDwnClass() {
12
13
  let messageStore;
13
14
  let dataStore;
14
15
  let resumableTaskStore;
15
- let stateIndex;
16
16
  let eventLog;
17
17
  let dwn;
18
18
  // important to follow the `beforeAll` and `afterAll` pattern to initialize and clean the stores in tests
@@ -23,9 +23,8 @@ export function testDwnClass() {
23
23
  messageStore = stores.messageStore;
24
24
  dataStore = stores.dataStore;
25
25
  resumableTaskStore = stores.resumableTaskStore;
26
- stateIndex = stores.stateIndex;
27
26
  eventLog = TestEventLog.get();
28
- dwn = await Dwn.create({ didResolver, messageStore, dataStore, stateIndex, eventLog, resumableTaskStore });
27
+ dwn = await Dwn.create({ didResolver, messageStore, dataStore, eventLog, resumableTaskStore });
29
28
  });
30
29
  beforeEach(async () => {
31
30
  sinon.restore(); // wipe all stubs/spies/mocks/fakes from previous test
@@ -81,15 +80,11 @@ export function testDwnClass() {
81
80
  const messageStoreStub = sinon.createStubInstance(MessageStoreLevel);
82
81
  const dataStoreStub = sinon.createStubInstance(DataStoreLevel);
83
82
  const resumableTaskStoreStub = sinon.createStubInstance(ResumableTaskStoreLevel);
84
- const stateIndexStub = sinon.createStubInstance(StateIndexLevel);
85
- const eventLogStub = sinon.createStubInstance(EventEmitterEventLog);
86
83
  const dwnWithConfig = await Dwn.create({
87
84
  tenantGate: blockAllTenantGate,
88
85
  messageStore: messageStoreStub,
89
86
  dataStore: dataStoreStub,
90
87
  resumableTaskStore: resumableTaskStoreStub,
91
- stateIndex: stateIndexStub,
92
- eventLog: eventLogStub
93
88
  });
94
89
  const alice = await TestDataGenerator.generateDidKeyPersona();
95
90
  const { author, message } = await TestDataGenerator.generateRecordsQuery({ author: alice });
@@ -109,15 +104,11 @@ export function testDwnClass() {
109
104
  const messageStoreStub = sinon.createStubInstance(MessageStoreLevel);
110
105
  const dataStoreStub = sinon.createStubInstance(DataStoreLevel);
111
106
  const resumableTaskStoreStub = sinon.createStubInstance(ResumableTaskStoreLevel);
112
- const stateIndexStub = sinon.createStubInstance(StateIndexLevel);
113
- const eventLogStub = sinon.createStubInstance(EventEmitterEventLog);
114
107
  const dwnWithConfig = await Dwn.create({
115
108
  tenantGate: blockAllTenantGate,
116
109
  messageStore: messageStoreStub,
117
110
  dataStore: dataStoreStub,
118
111
  resumableTaskStore: resumableTaskStoreStub,
119
- stateIndex: stateIndexStub,
120
- eventLog: eventLogStub
121
112
  });
122
113
  const alice = await TestDataGenerator.generateDidKeyPersona();
123
114
  const { author, message } = await TestDataGenerator.generateRecordsQuery({ author: alice });
@@ -128,34 +119,14 @@ export function testDwnClass() {
128
119
  });
129
120
  });
130
121
  describe('applyReplicatedMessage()', () => {
131
- it('returns Duplicate and repairs the state index for an exact replay already in the message store', async () => {
122
+ it('returns Duplicate for an exact replay already in the message store', async () => {
132
123
  const alice = await TestDataGenerator.generateDidKeyPersona();
133
124
  await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
134
125
  const { message, dataStream } = await TestDataGenerator.generateRecordsWrite({ author: alice });
135
126
  const initialReply = await dwn.processMessage(alice.did, message, { dataStream });
136
127
  expect(initialReply.status.code).toBe(202);
137
- const messageCid = await Message.getCid(message);
138
- await stateIndex.delete(alice.did, [messageCid]);
139
- expect(await stateIndex.getLeaves(alice.did, [])).not.toContain(messageCid);
140
128
  const result = await dwn.applyReplicatedMessage(alice.did, message);
141
129
  expect(result).toEqual({ kind: 'Duplicate' });
142
- expect(await stateIndex.getLeaves(alice.did, [])).toContain(messageCid);
143
- });
144
- it('returns Duplicate and repairs the event log for an exact replay already in the message store and state index', async () => {
145
- const alice = await TestDataGenerator.generateDidKeyPersona();
146
- await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
147
- const { message, dataStream } = await TestDataGenerator.generateRecordsWrite({ author: alice });
148
- const initialReply = await dwn.processMessage(alice.did, message, { dataStream });
149
- expect(initialReply.status.code).toBe(202);
150
- const messageCid = await Message.getCid(message);
151
- expect(await stateIndex.getLeaves(alice.did, [])).toContain(messageCid);
152
- await eventLog.close();
153
- await eventLog.open();
154
- expect((await eventLog.read(alice.did)).events).toEqual([]);
155
- const result = await dwn.applyReplicatedMessage(alice.did, message);
156
- expect(result).toEqual({ kind: 'Duplicate' });
157
- const { events } = await eventLog.read(alice.did);
158
- expect(events.map(event => event.messageCid)).toContain(messageCid);
159
130
  });
160
131
  it('returns resolved cross-protocol role dependencies for replicated role-authorized queries', async () => {
161
132
  const alice = await TestDataGenerator.generateDidKeyPersona();
@@ -205,7 +176,7 @@ export function testDwnClass() {
205
176
  author: bob,
206
177
  protocolRole: 'threads:thread/participant',
207
178
  filter: {
208
- contextId: 'thread-context/comment-context',
179
+ contextId: 'thread-context',
209
180
  protocol: commentsProtocol.protocol,
210
181
  protocolPath: 'thread/comment',
211
182
  },
@@ -263,6 +234,504 @@ export function testDwnClass() {
263
234
  const result = await dwn.applyReplicatedMessage(alice.did, child.message);
264
235
  expect(result).toEqual({ kind: 'Duplicate' });
265
236
  });
237
+ it('classifies a replicated write older than the squash floor as Superseded', async () => {
238
+ const alice = await TestDataGenerator.generateDidKeyPersona();
239
+ const squashProtocol = {
240
+ protocol: 'https://example.com/replicated-squash',
241
+ published: true,
242
+ types: {
243
+ document: {},
244
+ patch: {},
245
+ },
246
+ structure: {
247
+ document: {
248
+ patch: {
249
+ $immutable: true,
250
+ $squash: true,
251
+ },
252
+ },
253
+ },
254
+ };
255
+ const protocolsConfigure = await TestDataGenerator.generateProtocolsConfigure({
256
+ author: alice,
257
+ protocolDefinition: squashProtocol,
258
+ });
259
+ expect((await dwn.processMessage(alice.did, protocolsConfigure.message)).status.code).toBe(202);
260
+ const document = await TestDataGenerator.generateRecordsWrite({
261
+ author: alice,
262
+ protocol: squashProtocol.protocol,
263
+ protocolPath: 'document',
264
+ });
265
+ expect((await dwn.processMessage(alice.did, document.message, { dataStream: document.dataStream })).status.code).toBe(202);
266
+ const squashTimestamp = Time.createOffsetTimestamp({ seconds: 10 });
267
+ const squashRecord = await TestDataGenerator.generateRecordsWrite({
268
+ author: alice,
269
+ protocol: squashProtocol.protocol,
270
+ protocolPath: 'document/patch',
271
+ parentContextId: document.message.contextId,
272
+ dateCreated: squashTimestamp,
273
+ messageTimestamp: squashTimestamp,
274
+ squash: true,
275
+ });
276
+ expect((await dwn.processMessage(alice.did, squashRecord.message, { dataStream: squashRecord.dataStream })).status.code).toBe(202);
277
+ // A replica replaying a pre-squash write is a normal multi-replica race: it must
278
+ // converge as a no-op, never surface as a terminal failure.
279
+ const olderTimestamp = Time.createOffsetTimestamp({ seconds: 5 });
280
+ const olderPatch = await TestDataGenerator.generateRecordsWrite({
281
+ author: alice,
282
+ protocol: squashProtocol.protocol,
283
+ protocolPath: 'document/patch',
284
+ parentContextId: document.message.contextId,
285
+ dateCreated: olderTimestamp,
286
+ messageTimestamp: olderTimestamp,
287
+ });
288
+ const result = await dwn.applyReplicatedMessage(alice.did, olderPatch.message, { dataStream: olderPatch.dataStream });
289
+ expect(result).toEqual({ kind: 'Superseded' });
290
+ });
291
+ it('converges to the same deleted state when a write and an older tombstone apply in either order', async () => {
292
+ const alice = await TestDataGenerator.generateDidKeyPersona();
293
+ // one shared ProtocolsConfigure message, processed on BOTH replicas so their
294
+ // state roots remain directly comparable
295
+ const protocolsConfigure = await TestDataGenerator.generateProtocolsConfigure({
296
+ author: alice,
297
+ protocolDefinition: defaultTestProtocolDefinition,
298
+ });
299
+ expect((await dwn.processMessage(alice.did, protocolsConfigure.message)).status.code).toBe(202);
300
+ // initial write -> tombstone -> newer update, with strictly increasing timestamps
301
+ const datePublished = '2025-01-05T00:00:00.000000Z';
302
+ const initialWrite = await TestDataGenerator.generateRecordsWrite({ author: alice });
303
+ await Time.minimalSleep();
304
+ const recordsDelete = await RecordsDelete.create({
305
+ recordId: initialWrite.message.recordId,
306
+ signer: Jws.createSigner(alice),
307
+ });
308
+ await Time.minimalSleep();
309
+ const updateDataBytes = TestDataGenerator.randomBytes(32);
310
+ const update = await RecordsWrite.createFrom({
311
+ recordsWriteMessage: initialWrite.message,
312
+ data: updateDataBytes,
313
+ published: true,
314
+ datePublished,
315
+ tags: { team: 'blue' },
316
+ signer: Jws.createSigner(alice),
317
+ });
318
+ // replica A: initial write and the newer update land first, the older tombstone last
319
+ expect(await dwn.applyReplicatedMessage(alice.did, initialWrite.message, { dataStream: DataStream.fromBytes(initialWrite.dataBytes) })).toEqual(expect.objectContaining({ kind: 'Applied' }));
320
+ expect(await dwn.applyReplicatedMessage(alice.did, update.message, { dataStream: DataStream.fromBytes(updateDataBytes) })).toEqual(expect.objectContaining({ kind: 'Applied' }));
321
+ expect(await dwn.applyReplicatedMessage(alice.did, recordsDelete.message)).toEqual(expect.objectContaining({ kind: 'Applied' }));
322
+ // replica B: the tombstone lands before the newer update
323
+ const messageStoreB = new MessageStoreLevel({
324
+ location: 'TEST-MESSAGESTORE-DELETEWINS',
325
+ });
326
+ const dataStoreB = new DataStoreLevel({ blockstoreLocation: 'TEST-DATASTORE-DELETEWINS' });
327
+ const resumableTaskStoreB = new ResumableTaskStoreLevel({ location: 'TEST-RESUMABLE-TASK-STORE-DELETEWINS' });
328
+ const dwnB = await Dwn.create({
329
+ didResolver,
330
+ messageStore: messageStoreB,
331
+ dataStore: dataStoreB,
332
+ resumableTaskStore: resumableTaskStoreB,
333
+ });
334
+ try {
335
+ await messageStoreB.clear();
336
+ await dataStoreB.clear();
337
+ await resumableTaskStoreB.clear();
338
+ expect((await dwnB.processMessage(alice.did, protocolsConfigure.message)).status.code).toBe(202);
339
+ expect(await dwnB.applyReplicatedMessage(alice.did, initialWrite.message, { dataStream: DataStream.fromBytes(initialWrite.dataBytes) })).toEqual(expect.objectContaining({ kind: 'Applied' }));
340
+ expect(await dwnB.applyReplicatedMessage(alice.did, recordsDelete.message)).toEqual(expect.objectContaining({ kind: 'Applied' }));
341
+ expect(await dwnB.applyReplicatedMessage(alice.did, update.message, { dataStream: DataStream.fromBytes(updateDataBytes) })).toEqual({ kind: 'Superseded' });
342
+ // both replicas read the record as deleted and retain the update-derived tombstone visibility
343
+ const readA = await RecordsRead.create({
344
+ signer: Jws.createSigner(alice),
345
+ filter: { recordId: initialWrite.message.recordId },
346
+ });
347
+ expect((await dwn.processMessage(alice.did, readA.message)).status.code).toBe(404);
348
+ const readB = await RecordsRead.create({
349
+ signer: Jws.createSigner(alice),
350
+ filter: { recordId: initialWrite.message.recordId },
351
+ });
352
+ expect((await dwnB.processMessage(alice.did, readB.message)).status.code).toBe(404);
353
+ const tombstoneFilter = {
354
+ 'method': 'Delete',
355
+ 'tag.team': 'blue',
356
+ 'published': true,
357
+ 'datePublished': datePublished,
358
+ };
359
+ const { messages: tombstonesA } = await messageStore.query(alice.did, [tombstoneFilter]);
360
+ const { messages: tombstonesB } = await messageStoreB.query(alice.did, [tombstoneFilter]);
361
+ expect(tombstonesA.length).toBe(1);
362
+ expect(tombstonesB.length).toBe(1);
363
+ expect(await Message.getCid(tombstonesA[0])).toBe(await Message.getCid(recordsDelete.message));
364
+ expect(await Message.getCid(tombstonesB[0])).toBe(await Message.getCid(recordsDelete.message));
365
+ }
366
+ finally {
367
+ await dwnB.close();
368
+ }
369
+ });
370
+ it('rejects a tombstone-beaten replicated write when its data does not match its descriptor', async () => {
371
+ const alice = await TestDataGenerator.generateDidKeyPersona();
372
+ const protocolsConfigure = await TestDataGenerator.generateProtocolsConfigure({
373
+ author: alice,
374
+ protocolDefinition: defaultTestProtocolDefinition,
375
+ });
376
+ expect((await dwn.processMessage(alice.did, protocolsConfigure.message)).status.code).toBe(202);
377
+ const initialWrite = await TestDataGenerator.generateRecordsWrite({ author: alice });
378
+ expect(await dwn.applyReplicatedMessage(alice.did, initialWrite.message, { dataStream: DataStream.fromBytes(initialWrite.dataBytes) })).toEqual(expect.objectContaining({ kind: 'Applied' }));
379
+ const recordsDelete = await RecordsDelete.create({
380
+ recordId: initialWrite.message.recordId,
381
+ signer: Jws.createSigner(alice),
382
+ });
383
+ expect(await dwn.applyReplicatedMessage(alice.did, recordsDelete.message)).toEqual(expect.objectContaining({ kind: 'Applied' }));
384
+ await Time.minimalSleep();
385
+ const updateDataBytes = TestDataGenerator.randomBytes(32);
386
+ const update = await RecordsWrite.createFrom({
387
+ recordsWriteMessage: initialWrite.message,
388
+ data: updateDataBytes,
389
+ tags: { team: 'blue' },
390
+ signer: Jws.createSigner(alice),
391
+ });
392
+ const malformedDataBytes = TestDataGenerator.randomBytes(32);
393
+ const result = await dwn.applyReplicatedMessage(alice.did, update.message, { dataStream: DataStream.fromBytes(malformedDataBytes) });
394
+ expect(result.kind).toBe('Invalid');
395
+ expect(result.reason).toContain(DwnErrorCode.RecordsWriteDataCidMismatch);
396
+ const updateCid = await Message.getCid(update.message);
397
+ const { messages } = await messageStore.query(alice.did, [{ recordId: initialWrite.message.recordId }]);
398
+ const messageCids = await Promise.all(messages.map(message => Message.getCid(message)));
399
+ expect(messageCids).not.toContain(updateCid);
400
+ const { messages: reindexedTombstones } = await messageStore.query(alice.did, [{
401
+ method: DwnMethodName.Delete,
402
+ 'tag.team': 'blue',
403
+ }]);
404
+ expect(reindexedTombstones.length).toBe(0);
405
+ });
406
+ it('reports missing data for tombstone-beaten replicated writes without data', async () => {
407
+ const alice = await TestDataGenerator.generateDidKeyPersona();
408
+ await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
409
+ const scenarios = [
410
+ { dataBytes: TestDataGenerator.randomBytes(32), storage: 'inline' },
411
+ { dataBytes: TestDataGenerator.randomBytes(31_000), storage: 'data-store' },
412
+ ];
413
+ for (const { dataBytes, storage } of scenarios) {
414
+ const initialWrite = await TestDataGenerator.generateRecordsWrite({ author: alice, data: dataBytes });
415
+ expect(await dwn.applyReplicatedMessage(alice.did, initialWrite.message, { dataStream: DataStream.fromBytes(dataBytes) })).toEqual(expect.objectContaining({ kind: 'Applied' }));
416
+ const recordsDelete = await RecordsDelete.create({
417
+ recordId: initialWrite.message.recordId,
418
+ signer: Jws.createSigner(alice),
419
+ });
420
+ expect(await dwn.applyReplicatedMessage(alice.did, recordsDelete.message)).toEqual(expect.objectContaining({ kind: 'Applied' }));
421
+ await Time.minimalSleep();
422
+ const update = await RecordsWrite.createFrom({
423
+ recordsWriteMessage: initialWrite.message,
424
+ tags: { storage },
425
+ signer: Jws.createSigner(alice),
426
+ });
427
+ const result = await dwn.applyReplicatedMessage(alice.did, update.message);
428
+ expect(result).toEqual({
429
+ kind: 'Incomplete',
430
+ missing: [{
431
+ type: 'RecordData',
432
+ recordId: update.message.recordId,
433
+ dataCid: update.message.descriptor.dataCid,
434
+ protocol: update.message.descriptor.protocol,
435
+ }],
436
+ });
437
+ const updateCid = await Message.getCid(update.message);
438
+ expect(await messageStore.get(alice.did, updateCid)).toBeUndefined();
439
+ const { messages: reindexedTombstones } = await messageStore.query(alice.did, [{
440
+ method: DwnMethodName.Delete,
441
+ 'tag.storage': storage,
442
+ }]);
443
+ expect(reindexedTombstones.length).toBe(0);
444
+ }
445
+ });
446
+ it('accepts a tombstone-beaten replicated write with a valid large data stream', async () => {
447
+ const alice = await TestDataGenerator.generateDidKeyPersona();
448
+ await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
449
+ const initialWrite = await TestDataGenerator.generateRecordsWrite({ author: alice });
450
+ expect(await dwn.applyReplicatedMessage(alice.did, initialWrite.message, { dataStream: DataStream.fromBytes(initialWrite.dataBytes) })).toEqual(expect.objectContaining({ kind: 'Applied' }));
451
+ const recordsDelete = await RecordsDelete.create({
452
+ recordId: initialWrite.message.recordId,
453
+ signer: Jws.createSigner(alice),
454
+ });
455
+ expect(await dwn.applyReplicatedMessage(alice.did, recordsDelete.message)).toEqual(expect.objectContaining({ kind: 'Applied' }));
456
+ await Time.minimalSleep();
457
+ const updateDataBytes = TestDataGenerator.randomBytes(31_000);
458
+ const update = await RecordsWrite.createFrom({
459
+ recordsWriteMessage: initialWrite.message,
460
+ data: updateDataBytes,
461
+ tags: { storage: 'data-store' },
462
+ signer: Jws.createSigner(alice),
463
+ });
464
+ expect(await dwn.applyReplicatedMessage(alice.did, update.message, { dataStream: DataStream.fromBytes(updateDataBytes) })).toEqual({ kind: 'Superseded' });
465
+ const updateCid = await Message.getCid(update.message);
466
+ expect(await messageStore.get(alice.did, updateCid)).toBeDefined();
467
+ const { messages: reindexedTombstones } = await messageStore.query(alice.did, [{
468
+ method: DwnMethodName.Delete,
469
+ 'tag.storage': 'data-store',
470
+ }]);
471
+ expect(reindexedTombstones.length).toBe(1);
472
+ expect(await Message.getCid(reindexedTombstones[0])).toBe(await Message.getCid(recordsDelete.message));
473
+ });
474
+ it('applies the handler stale-tombstone gate on resumable-task replay', async () => {
475
+ const alice = await TestDataGenerator.generateDidKeyPersona();
476
+ await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
477
+ const initialWrite = await TestDataGenerator.generateRecordsWrite({ author: alice });
478
+ expect((await dwn.processMessage(alice.did, initialWrite.message, { dataStream: initialWrite.dataStream })).status.code).toBe(202);
479
+ // generate the losing delete first so it is older than the tombstone admitted below
480
+ const staleDelete = await RecordsDelete.create({
481
+ recordId: initialWrite.message.recordId,
482
+ signer: Jws.createSigner(alice),
483
+ });
484
+ await Time.minimalSleep();
485
+ const recordsDelete = await RecordsDelete.create({
486
+ recordId: initialWrite.message.recordId,
487
+ signer: Jws.createSigner(alice),
488
+ });
489
+ expect((await dwn.processMessage(alice.did, recordsDelete.message)).status.code).toBe(202);
490
+ // replaying the beaten delete through the task path must be a no-op — the same lattice
491
+ // gate as admission — leaving the canonical tombstone as the record's newest message
492
+ await dwn['storageController'].performRecordsDelete({ tenant: alice.did, message: staleDelete.message });
493
+ const tombstoneCid = await Message.getCid(recordsDelete.message);
494
+ const staleDeleteCid = await Message.getCid(staleDelete.message);
495
+ expect(await messageStore.get(alice.did, tombstoneCid)).toBeDefined();
496
+ expect(await messageStore.get(alice.did, staleDeleteCid)).toBeUndefined();
497
+ });
498
+ it('converges competing plain tombstones to one canonical winner in either order', async () => {
499
+ const alice = await TestDataGenerator.generateDidKeyPersona();
500
+ const protocolsConfigure = await TestDataGenerator.generateProtocolsConfigure({
501
+ author: alice,
502
+ protocolDefinition: defaultTestProtocolDefinition,
503
+ });
504
+ expect((await dwn.processMessage(alice.did, protocolsConfigure.message)).status.code).toBe(202);
505
+ // two independently authored plain tombstones for the same record, d1 older than d2
506
+ const initialWrite = await TestDataGenerator.generateRecordsWrite({ author: alice });
507
+ const d1 = await RecordsDelete.create({
508
+ recordId: initialWrite.message.recordId,
509
+ signer: Jws.createSigner(alice),
510
+ });
511
+ await Time.minimalSleep();
512
+ const d2 = await RecordsDelete.create({
513
+ recordId: initialWrite.message.recordId,
514
+ signer: Jws.createSigner(alice),
515
+ });
516
+ // replica A: d1 lands first, then d2 displaces it
517
+ expect(await dwn.applyReplicatedMessage(alice.did, initialWrite.message, { dataStream: DataStream.fromBytes(initialWrite.dataBytes) })).toEqual(expect.objectContaining({ kind: 'Applied' }));
518
+ expect(await dwn.applyReplicatedMessage(alice.did, d1.message)).toEqual(expect.objectContaining({ kind: 'Applied' }));
519
+ expect(await dwn.applyReplicatedMessage(alice.did, d2.message)).toEqual(expect.objectContaining({ kind: 'Applied' }));
520
+ // replica B: d2 lands first; the beaten d1 converges as a Superseded no-op
521
+ const messageStoreB = new MessageStoreLevel({
522
+ location: 'TEST-MESSAGESTORE-DELETEWINS',
523
+ });
524
+ const dataStoreB = new DataStoreLevel({ blockstoreLocation: 'TEST-DATASTORE-DELETEWINS' });
525
+ const resumableTaskStoreB = new ResumableTaskStoreLevel({ location: 'TEST-RESUMABLE-TASK-STORE-DELETEWINS' });
526
+ const dwnB = await Dwn.create({
527
+ didResolver,
528
+ messageStore: messageStoreB,
529
+ dataStore: dataStoreB,
530
+ resumableTaskStore: resumableTaskStoreB,
531
+ });
532
+ try {
533
+ await messageStoreB.clear();
534
+ await dataStoreB.clear();
535
+ await resumableTaskStoreB.clear();
536
+ expect((await dwnB.processMessage(alice.did, protocolsConfigure.message)).status.code).toBe(202);
537
+ expect(await dwnB.applyReplicatedMessage(alice.did, initialWrite.message, { dataStream: DataStream.fromBytes(initialWrite.dataBytes) })).toEqual(expect.objectContaining({ kind: 'Applied' }));
538
+ expect(await dwnB.applyReplicatedMessage(alice.did, d2.message)).toEqual(expect.objectContaining({ kind: 'Applied' }));
539
+ expect(await dwnB.applyReplicatedMessage(alice.did, d1.message)).toEqual({ kind: 'Superseded' });
540
+ // both replicas hold d2 as the canonical tombstone
541
+ const d1Cid = await Message.getCid(d1.message);
542
+ const d2Cid = await Message.getCid(d2.message);
543
+ expect(await messageStore.get(alice.did, d2Cid)).toBeDefined();
544
+ expect(await messageStore.get(alice.did, d1Cid)).toBeUndefined();
545
+ expect(await messageStoreB.get(alice.did, d2Cid)).toBeDefined();
546
+ expect(await messageStoreB.get(alice.did, d1Cid)).toBeUndefined();
547
+ }
548
+ finally {
549
+ await dwnB.close();
550
+ }
551
+ });
552
+ it('a prune beats a newer plain delete in either order and purges descendants on both replicas', async () => {
553
+ const alice = await TestDataGenerator.generateDidKeyPersona();
554
+ const nestedProtocolDefinition = nestedProtocol;
555
+ const protocolsConfigure = await TestDataGenerator.generateProtocolsConfigure({
556
+ author: alice,
557
+ protocolDefinition: nestedProtocolDefinition,
558
+ });
559
+ expect((await dwn.processMessage(alice.did, protocolsConfigure.message)).status.code).toBe(202);
560
+ // parent foo with child bar, then a prune of foo and a NEWER plain delete of foo
561
+ const foo = await TestDataGenerator.generateRecordsWrite({
562
+ author: alice,
563
+ protocol: nestedProtocolDefinition.protocol,
564
+ protocolPath: 'foo',
565
+ schema: nestedProtocolDefinition.types.foo.schema,
566
+ dataFormat: nestedProtocolDefinition.types.foo.dataFormats[0],
567
+ });
568
+ const bar = await TestDataGenerator.generateRecordsWrite({
569
+ author: alice,
570
+ protocol: nestedProtocolDefinition.protocol,
571
+ protocolPath: 'foo/bar',
572
+ parentContextId: foo.message.contextId,
573
+ schema: nestedProtocolDefinition.types.bar.schema,
574
+ dataFormat: nestedProtocolDefinition.types.bar.dataFormats[0],
575
+ });
576
+ const prune = await RecordsDelete.create({
577
+ recordId: foo.message.recordId,
578
+ prune: true,
579
+ signer: Jws.createSigner(alice),
580
+ });
581
+ await Time.minimalSleep();
582
+ const plainDelete = await RecordsDelete.create({
583
+ recordId: foo.message.recordId,
584
+ signer: Jws.createSigner(alice),
585
+ });
586
+ // replica A: prune first, then the newer plain delete loses on class
587
+ expect(await dwn.applyReplicatedMessage(alice.did, foo.message, { dataStream: DataStream.fromBytes(foo.dataBytes) })).toEqual(expect.objectContaining({ kind: 'Applied' }));
588
+ expect(await dwn.applyReplicatedMessage(alice.did, bar.message, { dataStream: DataStream.fromBytes(bar.dataBytes) })).toEqual(expect.objectContaining({ kind: 'Applied' }));
589
+ expect(await dwn.applyReplicatedMessage(alice.did, prune.message)).toEqual(expect.objectContaining({ kind: 'Applied' }));
590
+ expect(await dwn.applyReplicatedMessage(alice.did, plainDelete.message)).toEqual({ kind: 'Superseded' });
591
+ // replica B: the newer plain delete lands first; the prune still wins and cascades
592
+ const messageStoreB = new MessageStoreLevel({
593
+ location: 'TEST-MESSAGESTORE-DELETEWINS',
594
+ });
595
+ const dataStoreB = new DataStoreLevel({ blockstoreLocation: 'TEST-DATASTORE-DELETEWINS' });
596
+ const resumableTaskStoreB = new ResumableTaskStoreLevel({ location: 'TEST-RESUMABLE-TASK-STORE-DELETEWINS' });
597
+ const dwnB = await Dwn.create({
598
+ didResolver,
599
+ messageStore: messageStoreB,
600
+ dataStore: dataStoreB,
601
+ resumableTaskStore: resumableTaskStoreB,
602
+ });
603
+ try {
604
+ await messageStoreB.clear();
605
+ await dataStoreB.clear();
606
+ await resumableTaskStoreB.clear();
607
+ expect((await dwnB.processMessage(alice.did, protocolsConfigure.message)).status.code).toBe(202);
608
+ expect(await dwnB.applyReplicatedMessage(alice.did, foo.message, { dataStream: DataStream.fromBytes(foo.dataBytes) })).toEqual(expect.objectContaining({ kind: 'Applied' }));
609
+ expect(await dwnB.applyReplicatedMessage(alice.did, bar.message, { dataStream: DataStream.fromBytes(bar.dataBytes) })).toEqual(expect.objectContaining({ kind: 'Applied' }));
610
+ expect(await dwnB.applyReplicatedMessage(alice.did, plainDelete.message)).toEqual(expect.objectContaining({ kind: 'Applied' }));
611
+ expect(await dwnB.applyReplicatedMessage(alice.did, prune.message)).toEqual(expect.objectContaining({ kind: 'Applied' }));
612
+ // the child is purged on both replicas
613
+ const barCid = await Message.getCid(bar.message);
614
+ expect(await messageStore.get(alice.did, barCid)).toBeUndefined();
615
+ expect(await messageStoreB.get(alice.did, barCid)).toBeUndefined();
616
+ }
617
+ finally {
618
+ await dwnB.close();
619
+ }
620
+ });
621
+ const deepNestedProtocol = {
622
+ protocol: 'https://example.com/deep-nested',
623
+ published: false,
624
+ types: {
625
+ foo: {},
626
+ bar: {},
627
+ baz: {},
628
+ qux: {},
629
+ },
630
+ structure: {
631
+ foo: {
632
+ bar: {
633
+ baz: {
634
+ qux: {},
635
+ },
636
+ },
637
+ },
638
+ },
639
+ };
640
+ // Installs `deepNestedProtocol` on the local DWN and builds a foo -> bar -> baz -> qux
641
+ // record chain under it. None of the generated records are stored; each test applies the
642
+ // subset it needs to shape local ancestor presence.
643
+ async function generateDeepNestedChain(alice) {
644
+ const protocolsConfigure = await TestDataGenerator.generateProtocolsConfigure({
645
+ author: alice,
646
+ protocolDefinition: deepNestedProtocol,
647
+ });
648
+ expect((await dwn.processMessage(alice.did, protocolsConfigure.message)).status.code).toBe(202);
649
+ const foo = await TestDataGenerator.generateRecordsWrite({
650
+ author: alice,
651
+ protocol: deepNestedProtocol.protocol,
652
+ protocolPath: 'foo',
653
+ });
654
+ const bar = await TestDataGenerator.generateRecordsWrite({
655
+ author: alice,
656
+ protocol: deepNestedProtocol.protocol,
657
+ protocolPath: 'foo/bar',
658
+ parentContextId: foo.message.contextId,
659
+ });
660
+ const baz = await TestDataGenerator.generateRecordsWrite({
661
+ author: alice,
662
+ protocol: deepNestedProtocol.protocol,
663
+ protocolPath: 'foo/bar/baz',
664
+ parentContextId: bar.message.contextId,
665
+ });
666
+ const qux = await TestDataGenerator.generateRecordsWrite({
667
+ author: alice,
668
+ protocol: deepNestedProtocol.protocol,
669
+ protocolPath: 'foo/bar/baz/qux',
670
+ parentContextId: baz.message.contextId,
671
+ });
672
+ return { foo, bar, baz, qux };
673
+ }
674
+ it('emits one ref per missing contextId segment in a single Incomplete', async () => {
675
+ const alice = await TestDataGenerator.generateDidKeyPersona();
676
+ const { foo, bar, baz, qux } = await generateDeepNestedChain(alice);
677
+ // no ancestors are present locally: a single apply names every missing segment,
678
+ // root-first, with the immediate parent keeping its existing Parent ref shape
679
+ const result = await dwn.applyReplicatedMessage(alice.did, qux.message, { dataStream: DataStream.fromBytes(qux.dataBytes) });
680
+ expect(result).toEqual({
681
+ kind: 'Incomplete',
682
+ missing: [
683
+ { type: 'Ancestor', recordId: foo.message.recordId, protocol: deepNestedProtocol.protocol },
684
+ { type: 'Ancestor', recordId: bar.message.recordId, protocol: deepNestedProtocol.protocol },
685
+ { type: 'Parent', recordId: baz.message.recordId, protocol: deepNestedProtocol.protocol },
686
+ ],
687
+ });
688
+ });
689
+ it('lists only the locally-missing ancestor segments when part of the chain is present', async () => {
690
+ const alice = await TestDataGenerator.generateDidKeyPersona();
691
+ const { foo, bar, baz, qux } = await generateDeepNestedChain(alice);
692
+ // the root of the chain is already present locally
693
+ expect(await dwn.applyReplicatedMessage(alice.did, foo.message, { dataStream: DataStream.fromBytes(foo.dataBytes) })).toEqual(expect.objectContaining({ kind: 'Applied' }));
694
+ const result = await dwn.applyReplicatedMessage(alice.did, qux.message, { dataStream: DataStream.fromBytes(qux.dataBytes) });
695
+ expect(result).toEqual({
696
+ kind: 'Incomplete',
697
+ missing: [
698
+ { type: 'Ancestor', recordId: bar.message.recordId, protocol: deepNestedProtocol.protocol },
699
+ { type: 'Parent', recordId: baz.message.recordId, protocol: deepNestedProtocol.protocol },
700
+ ],
701
+ });
702
+ });
703
+ it('resolves a deep ancestor chain in a bounded number of fetch-and-retry passes', async () => {
704
+ const alice = await TestDataGenerator.generateDidKeyPersona();
705
+ const { foo, bar, baz, qux } = await generateDeepNestedChain(alice);
706
+ const chainWritesByRecordId = new Map([
707
+ [foo.message.recordId, foo],
708
+ [bar.message.recordId, bar],
709
+ [baz.message.recordId, baz],
710
+ ]);
711
+ // engine loop: apply the deepest record, fetch whatever the Incomplete names, retry
712
+ let applyAttempts = 0;
713
+ let result;
714
+ do {
715
+ applyAttempts += 1;
716
+ result = await dwn.applyReplicatedMessage(alice.did, qux.message, { dataStream: DataStream.fromBytes(qux.dataBytes) });
717
+ if (result.kind === 'Incomplete') {
718
+ for (const ref of result.missing) {
719
+ if (ref.type !== 'Ancestor' && ref.type !== 'Parent') {
720
+ throw new Error(`Incomplete named an unexpected dependency ref type: ${ref.type}`);
721
+ }
722
+ const ancestor = chainWritesByRecordId.get(ref.recordId);
723
+ if (ancestor === undefined) {
724
+ throw new Error(`Incomplete named an unexpected ancestor: ${ref.recordId}`);
725
+ }
726
+ expect(await dwn.applyReplicatedMessage(alice.did, ancestor.message, { dataStream: DataStream.fromBytes(ancestor.dataBytes) })).toEqual(expect.objectContaining({ kind: 'Applied' }));
727
+ }
728
+ }
729
+ } while (result.kind === 'Incomplete' && applyAttempts < 4);
730
+ // the full 4-level chain resolves in two passes — one Incomplete naming all three
731
+ // ancestors, then a clean apply — never one round trip per ancestry level
732
+ expect(result).toEqual(expect.objectContaining({ kind: 'Applied' }));
733
+ expect(applyAttempts).toBe(2);
734
+ });
266
735
  });
267
736
  });
268
737
  }