@enbox/dwn-sdk-js 0.3.9 → 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 (525) hide show
  1. package/README.md +4 -4
  2. package/dist/browser.mjs +11 -11
  3. package/dist/browser.mjs.map +4 -4
  4. package/dist/esm/generated/precompiled-validators.js +783 -1206
  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 +13 -7
  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 -61
  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 +31 -69
  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 +295 -0
  28. package/dist/esm/src/core/replication-apply.js.map +1 -0
  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 +261 -16
  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 +7 -8
  64. package/dist/esm/src/index.js.map +1 -1
  65. package/dist/esm/src/interfaces/messages-query.js +49 -0
  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 +274 -0
  113. package/dist/esm/tests/core/replication-apply.spec.js.map +1 -0
  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 +620 -14
  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 +84 -38
  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 -4
  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 +13 -7
  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 -15
  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 +129 -0
  244. package/dist/types/src/core/replication-apply.d.ts.map +1 -0
  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 +47 -13
  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 +16 -18
  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 -55
  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-apply.spec.d.ts +2 -0
  330. package/dist/types/tests/core/replication-apply.spec.d.ts.map +1 -0
  331. package/dist/types/tests/core/replication-replay-property.spec.d.ts +2 -0
  332. package/dist/types/tests/core/replication-replay-property.spec.d.ts.map +1 -0
  333. package/dist/types/tests/core/validation-read-closure.spec.d.ts +2 -0
  334. package/dist/types/tests/core/validation-read-closure.spec.d.ts.map +1 -0
  335. package/dist/types/tests/core/validation-state-reader.spec.d.ts +2 -0
  336. package/dist/types/tests/core/validation-state-reader.spec.d.ts.map +1 -0
  337. package/dist/types/tests/durable-event-log.spec.d.ts +2 -0
  338. package/dist/types/tests/durable-event-log.spec.d.ts.map +1 -0
  339. package/dist/types/tests/dwn.spec.d.ts.map +1 -1
  340. package/dist/types/tests/features/author-delegated-grant.spec.d.ts.map +1 -1
  341. package/dist/types/tests/features/owner-delegated-grant.spec.d.ts.map +1 -1
  342. package/dist/types/tests/features/owner-signature.spec.d.ts.map +1 -1
  343. package/dist/types/tests/features/permissions.spec.d.ts.map +1 -1
  344. package/dist/types/tests/features/protocol-composition.spec.d.ts.map +1 -1
  345. package/dist/types/tests/features/protocol-create-action.spec.d.ts.map +1 -1
  346. package/dist/types/tests/features/protocol-delete-action.spec.d.ts.map +1 -1
  347. package/dist/types/tests/features/protocol-update-action.spec.d.ts.map +1 -1
  348. package/dist/types/tests/features/records-delivery.spec.d.ts.map +1 -1
  349. package/dist/types/tests/features/records-immutable.spec.d.ts.map +1 -1
  350. package/dist/types/tests/features/records-nested-query-scope.spec.d.ts +2 -0
  351. package/dist/types/tests/features/records-nested-query-scope.spec.d.ts.map +1 -0
  352. package/dist/types/tests/features/records-prune-cross-protocol.spec.d.ts.map +1 -1
  353. package/dist/types/tests/features/records-prune.spec.d.ts.map +1 -1
  354. package/dist/types/tests/features/records-record-limit.spec.d.ts.map +1 -1
  355. package/dist/types/tests/features/records-squash.spec.d.ts.map +1 -1
  356. package/dist/types/tests/features/records-tags.spec.d.ts.map +1 -1
  357. package/dist/types/tests/features/resumable-tasks.spec.d.ts.map +1 -1
  358. package/dist/types/tests/handlers/messages-query.spec.d.ts +2 -0
  359. package/dist/types/tests/handlers/messages-query.spec.d.ts.map +1 -0
  360. package/dist/types/tests/handlers/messages-read.spec.d.ts.map +1 -1
  361. package/dist/types/tests/handlers/messages-subscribe.spec.d.ts.map +1 -1
  362. package/dist/types/tests/handlers/protocols-configure.spec.d.ts.map +1 -1
  363. package/dist/types/tests/handlers/protocols-query.spec.d.ts.map +1 -1
  364. package/dist/types/tests/handlers/records-count.spec.d.ts.map +1 -1
  365. package/dist/types/tests/handlers/records-delete.spec.d.ts.map +1 -1
  366. package/dist/types/tests/handlers/records-query.spec.d.ts.map +1 -1
  367. package/dist/types/tests/handlers/records-read.spec.d.ts.map +1 -1
  368. package/dist/types/tests/handlers/records-subscribe.spec.d.ts.map +1 -1
  369. package/dist/types/tests/handlers/records-write.spec.d.ts.map +1 -1
  370. package/dist/types/tests/scenarios/deleted-record.spec.d.ts.map +1 -1
  371. package/dist/types/tests/scenarios/end-to-end-tests.spec.d.ts.map +1 -1
  372. package/dist/types/tests/scenarios/nested-roles.spec.d.ts.map +1 -1
  373. package/dist/types/tests/scenarios/subscriptions.spec.d.ts.map +1 -1
  374. package/dist/types/tests/store/message-store.spec.d.ts.map +1 -1
  375. package/dist/types/tests/test-event-stream.d.ts +1 -1
  376. package/dist/types/tests/test-event-stream.d.ts.map +1 -1
  377. package/dist/types/tests/test-stores.d.ts +5 -4
  378. package/dist/types/tests/test-stores.d.ts.map +1 -1
  379. package/dist/types/tests/test-suite.d.ts +1 -2
  380. package/dist/types/tests/test-suite.d.ts.map +1 -1
  381. package/dist/types/tests/utils/test-data-generator.d.ts +20 -1
  382. package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -1
  383. package/dist/types/tests/utils/test-validation-state-reader.d.ts +15 -0
  384. package/dist/types/tests/utils/test-validation-state-reader.d.ts.map +1 -0
  385. package/package.json +2 -2
  386. package/src/core/core-protocol.ts +3 -3
  387. package/src/core/dwn-constant.ts +7 -1
  388. package/src/core/dwn-error.ts +13 -7
  389. package/src/core/grant-authorization.ts +11 -20
  390. package/src/core/message-reply.ts +6 -5
  391. package/src/core/messages-grant-authorization.ts +37 -100
  392. package/src/core/protocol-authorization-action.ts +29 -38
  393. package/src/core/protocol-authorization-validation.ts +41 -98
  394. package/src/core/protocol-authorization.ts +56 -202
  395. package/src/core/protocols-grant-authorization.ts +9 -9
  396. package/src/core/recording-validation-state-reader.ts +130 -0
  397. package/src/core/records-grant-authorization.ts +16 -16
  398. package/src/core/replication-apply.ts +412 -0
  399. package/src/core/resumable-task-manager.ts +10 -8
  400. package/src/core/validation-state-reader.ts +350 -0
  401. package/src/dwn.ts +417 -30
  402. package/src/enums/dwn-interface-method.ts +0 -1
  403. package/src/event-stream/durable-event-log.ts +509 -0
  404. package/src/event-stream/event-emitter-wake-publisher.ts +34 -0
  405. package/src/handlers/messages-query.ts +203 -0
  406. package/src/handlers/messages-read.ts +9 -10
  407. package/src/handlers/messages-subscribe.ts +12 -13
  408. package/src/handlers/protocols-configure.ts +37 -58
  409. package/src/handlers/protocols-query.ts +1 -1
  410. package/src/handlers/records-count.ts +24 -17
  411. package/src/handlers/records-delete.ts +29 -27
  412. package/src/handlers/records-query.ts +38 -17
  413. package/src/handlers/records-read.ts +63 -50
  414. package/src/handlers/records-subscribe.ts +132 -19
  415. package/src/handlers/records-write.ts +77 -168
  416. package/src/index.ts +16 -20
  417. package/src/interfaces/messages-query.ts +70 -0
  418. package/src/interfaces/protocols-configure.ts +12 -4
  419. package/src/interfaces/protocols-query.ts +4 -5
  420. package/src/interfaces/records-count.ts +9 -4
  421. package/src/interfaces/records-delete.ts +25 -5
  422. package/src/interfaces/records-query.ts +9 -4
  423. package/src/interfaces/records-read.ts +4 -4
  424. package/src/interfaces/records-subscribe.ts +9 -4
  425. package/src/interfaces/records-write.ts +41 -13
  426. package/src/protocols/permissions.ts +32 -52
  427. package/src/store/index-level.ts +30 -9
  428. package/src/store/level-wrapper.ts +9 -1
  429. package/src/store/message-store-level.ts +757 -47
  430. package/src/store/storage-controller.ts +74 -63
  431. package/src/types/message-store.ts +45 -2
  432. package/src/types/message-types.ts +3 -1
  433. package/src/types/messages-types.ts +26 -65
  434. package/src/types/method-handler.ts +3 -3
  435. package/src/types/permission-types.ts +1 -1
  436. package/src/types/subscriptions.ts +53 -42
  437. package/src/types/validation-state-reader.ts +127 -0
  438. package/src/utils/messages.ts +25 -1
  439. package/src/utils/record-limit-occupancy.ts +377 -0
  440. package/src/utils/records.ts +69 -13
  441. package/src/utils/replication.ts +122 -0
  442. package/dist/esm/src/core/record-chain.js +0 -64
  443. package/dist/esm/src/core/record-chain.js.map +0 -1
  444. package/dist/esm/src/event-stream/event-emitter-event-log.js +0 -334
  445. package/dist/esm/src/event-stream/event-emitter-event-log.js.map +0 -1
  446. package/dist/esm/src/handlers/messages-sync.js +0 -581
  447. package/dist/esm/src/handlers/messages-sync.js.map +0 -1
  448. package/dist/esm/src/interfaces/messages-sync.js +0 -54
  449. package/dist/esm/src/interfaces/messages-sync.js.map +0 -1
  450. package/dist/esm/src/smt/smt-store-level.js +0 -103
  451. package/dist/esm/src/smt/smt-store-level.js.map +0 -1
  452. package/dist/esm/src/smt/smt-store-memory.js +0 -41
  453. package/dist/esm/src/smt/smt-store-memory.js.map +0 -1
  454. package/dist/esm/src/smt/smt-utils.js +0 -129
  455. package/dist/esm/src/smt/smt-utils.js.map +0 -1
  456. package/dist/esm/src/smt/sparse-merkle-tree.js +0 -577
  457. package/dist/esm/src/smt/sparse-merkle-tree.js.map +0 -1
  458. package/dist/esm/src/state-index/state-index-level.js +0 -191
  459. package/dist/esm/src/state-index/state-index-level.js.map +0 -1
  460. package/dist/esm/src/sync/records-projection.js +0 -228
  461. package/dist/esm/src/sync/records-projection.js.map +0 -1
  462. package/dist/esm/src/types/smt-types.js +0 -5
  463. package/dist/esm/src/types/smt-types.js.map +0 -1
  464. package/dist/esm/src/types/state-index.js +0 -2
  465. package/dist/esm/src/types/state-index.js.map +0 -1
  466. package/dist/esm/tests/event-emitter-event-log.spec.js +0 -499
  467. package/dist/esm/tests/event-emitter-event-log.spec.js.map +0 -1
  468. package/dist/esm/tests/handlers/messages-sync.spec.js +0 -1771
  469. package/dist/esm/tests/handlers/messages-sync.spec.js.map +0 -1
  470. package/dist/esm/tests/smt/smt-store-level.spec.js +0 -132
  471. package/dist/esm/tests/smt/smt-store-level.spec.js.map +0 -1
  472. package/dist/esm/tests/smt/sparse-merkle-tree.spec.js +0 -732
  473. package/dist/esm/tests/smt/sparse-merkle-tree.spec.js.map +0 -1
  474. package/dist/esm/tests/state-index/state-index-level.spec.js +0 -245
  475. package/dist/esm/tests/state-index/state-index-level.spec.js.map +0 -1
  476. package/dist/esm/tests/sync/records-projection.spec.js +0 -245
  477. package/dist/esm/tests/sync/records-projection.spec.js.map +0 -1
  478. package/dist/types/src/core/record-chain.d.ts +0 -24
  479. package/dist/types/src/core/record-chain.d.ts.map +0 -1
  480. package/dist/types/src/event-stream/event-emitter-event-log.d.ts +0 -80
  481. package/dist/types/src/event-stream/event-emitter-event-log.d.ts.map +0 -1
  482. package/dist/types/src/handlers/messages-sync.d.ts +0 -83
  483. package/dist/types/src/handlers/messages-sync.d.ts.map +0 -1
  484. package/dist/types/src/interfaces/messages-sync.d.ts +0 -23
  485. package/dist/types/src/interfaces/messages-sync.d.ts.map +0 -1
  486. package/dist/types/src/smt/smt-store-level.d.ts +0 -32
  487. package/dist/types/src/smt/smt-store-level.d.ts.map +0 -1
  488. package/dist/types/src/smt/smt-store-memory.d.ts +0 -22
  489. package/dist/types/src/smt/smt-store-memory.d.ts.map +0 -1
  490. package/dist/types/src/smt/smt-utils.d.ts +0 -58
  491. package/dist/types/src/smt/smt-utils.d.ts.map +0 -1
  492. package/dist/types/src/smt/sparse-merkle-tree.d.ts +0 -124
  493. package/dist/types/src/smt/sparse-merkle-tree.d.ts.map +0 -1
  494. package/dist/types/src/state-index/state-index-level.d.ts +0 -83
  495. package/dist/types/src/state-index/state-index-level.d.ts.map +0 -1
  496. package/dist/types/src/sync/records-projection.d.ts +0 -98
  497. package/dist/types/src/sync/records-projection.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/dist/types/tests/sync/records-projection.spec.d.ts +0 -2
  513. package/dist/types/tests/sync/records-projection.spec.d.ts.map +0 -1
  514. package/src/core/record-chain.ts +0 -99
  515. package/src/event-stream/event-emitter-event-log.ts +0 -430
  516. package/src/handlers/messages-sync.ts +0 -896
  517. package/src/interfaces/messages-sync.ts +0 -86
  518. package/src/smt/smt-store-level.ts +0 -143
  519. package/src/smt/smt-store-memory.ts +0 -53
  520. package/src/smt/smt-utils.ts +0 -149
  521. package/src/smt/sparse-merkle-tree.ts +0 -698
  522. package/src/state-index/state-index-level.ts +0 -239
  523. package/src/sync/records-projection.ts +0 -328
  524. package/src/types/smt-types.ts +0 -95
  525. package/src/types/state-index.ts +0 -100
@@ -1,10 +1,11 @@
1
1
  import sinon from 'sinon';
2
- import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'bun:test';
3
- import { DataStoreLevel, EventEmitterEventLog, MessageStoreLevel, ResumableTaskStoreLevel, StateIndexLevel } from '../src/index.js';
2
+ import nestedProtocol from './vectors/protocol-definitions/nested.json' with { type: 'json' };
4
3
  import { Dwn } from '../src/dwn.js';
5
- import { TestDataGenerator } from './utils/test-data-generator.js';
6
4
  import { TestEventLog } from './test-event-stream.js';
7
5
  import { TestStores } from './test-stores.js';
6
+ import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'bun:test';
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 });
@@ -127,6 +118,621 @@ export function testDwnClass() {
127
118
  expect(reply.status.detail).toBe(customMessage);
128
119
  });
129
120
  });
121
+ describe('applyReplicatedMessage()', () => {
122
+ it('returns Duplicate for an exact replay already in the message store', async () => {
123
+ const alice = await TestDataGenerator.generateDidKeyPersona();
124
+ await TestDataGenerator.installDefaultTestProtocol(dwn, alice);
125
+ const { message, dataStream } = await TestDataGenerator.generateRecordsWrite({ author: alice });
126
+ const initialReply = await dwn.processMessage(alice.did, message, { dataStream });
127
+ expect(initialReply.status.code).toBe(202);
128
+ const result = await dwn.applyReplicatedMessage(alice.did, message);
129
+ expect(result).toEqual({ kind: 'Duplicate' });
130
+ });
131
+ it('returns resolved cross-protocol role dependencies for replicated role-authorized queries', async () => {
132
+ const alice = await TestDataGenerator.generateDidKeyPersona();
133
+ const bob = await TestDataGenerator.generateDidKeyPersona();
134
+ const threadsProtocol = {
135
+ protocol: 'https://threads.example.com',
136
+ published: true,
137
+ types: {
138
+ participant: {},
139
+ thread: {},
140
+ },
141
+ structure: {
142
+ thread: {
143
+ participant: {
144
+ $role: true,
145
+ },
146
+ },
147
+ },
148
+ };
149
+ const commentsProtocol = {
150
+ protocol: 'https://comments.example.com',
151
+ published: true,
152
+ uses: {
153
+ threads: threadsProtocol.protocol,
154
+ },
155
+ types: {
156
+ comment: {},
157
+ },
158
+ structure: {
159
+ thread: {
160
+ $ref: 'threads:thread',
161
+ comment: {},
162
+ },
163
+ },
164
+ };
165
+ const threadsConfigure = await TestDataGenerator.generateProtocolsConfigure({
166
+ author: alice,
167
+ protocolDefinition: threadsProtocol,
168
+ });
169
+ expect((await dwn.processMessage(alice.did, threadsConfigure.message)).status.code).toBe(202);
170
+ const commentsConfigure = await TestDataGenerator.generateProtocolsConfigure({
171
+ author: alice,
172
+ protocolDefinition: commentsProtocol,
173
+ });
174
+ expect((await dwn.processMessage(alice.did, commentsConfigure.message)).status.code).toBe(202);
175
+ const query = await TestDataGenerator.generateRecordsQuery({
176
+ author: bob,
177
+ protocolRole: 'threads:thread/participant',
178
+ filter: {
179
+ contextId: 'thread-context',
180
+ protocol: commentsProtocol.protocol,
181
+ protocolPath: 'thread/comment',
182
+ },
183
+ });
184
+ const result = await dwn.applyReplicatedMessage(alice.did, query.message);
185
+ expect(result).toEqual({
186
+ kind: 'Incomplete',
187
+ missing: [{
188
+ type: 'Role',
189
+ contextPrefix: 'thread-context',
190
+ protocol: threadsProtocol.protocol,
191
+ protocolPath: 'thread/participant',
192
+ recipient: bob.did,
193
+ }],
194
+ });
195
+ });
196
+ it('classifies exact child replay as Duplicate before checking that the parent is still active', async () => {
197
+ const alice = await TestDataGenerator.generateDidKeyPersona();
198
+ const nestedProtocol = {
199
+ protocol: 'https://example.com/nested-duplicate',
200
+ published: false,
201
+ types: {
202
+ parent: {},
203
+ child: {},
204
+ },
205
+ structure: {
206
+ parent: {
207
+ child: {},
208
+ },
209
+ },
210
+ };
211
+ const protocolsConfigure = await TestDataGenerator.generateProtocolsConfigure({
212
+ author: alice,
213
+ protocolDefinition: nestedProtocol,
214
+ });
215
+ expect((await dwn.processMessage(alice.did, protocolsConfigure.message)).status.code).toBe(202);
216
+ const parent = await TestDataGenerator.generateRecordsWrite({
217
+ author: alice,
218
+ protocol: nestedProtocol.protocol,
219
+ protocolPath: 'parent',
220
+ });
221
+ expect((await dwn.processMessage(alice.did, parent.message, { dataStream: parent.dataStream })).status.code).toBe(202);
222
+ const child = await TestDataGenerator.generateRecordsWrite({
223
+ author: alice,
224
+ protocol: nestedProtocol.protocol,
225
+ protocolPath: 'parent/child',
226
+ parentContextId: parent.message.contextId,
227
+ });
228
+ expect((await dwn.processMessage(alice.did, child.message, { dataStream: child.dataStream })).status.code).toBe(202);
229
+ const parentDelete = await TestDataGenerator.generateRecordsDelete({
230
+ author: alice,
231
+ recordId: parent.message.recordId,
232
+ });
233
+ expect((await dwn.processMessage(alice.did, parentDelete.message)).status.code).toBe(202);
234
+ const result = await dwn.applyReplicatedMessage(alice.did, child.message);
235
+ expect(result).toEqual({ kind: 'Duplicate' });
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
+ });
735
+ });
130
736
  });
131
737
  }
132
738
  //# sourceMappingURL=dwn.spec.js.map