@enbox/dwn-sdk-js 0.0.5 → 0.0.7

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 (363) hide show
  1. package/dist/browser.mjs +8 -8
  2. package/dist/browser.mjs.map +4 -4
  3. package/dist/esm/generated/precompiled-validators.js +1 -2
  4. package/dist/esm/generated/precompiled-validators.js.map +1 -1
  5. package/dist/esm/src/core/abstract-message.js +4 -0
  6. package/dist/esm/src/core/abstract-message.js.map +1 -1
  7. package/dist/esm/src/core/auth.js +22 -33
  8. package/dist/esm/src/core/auth.js.map +1 -1
  9. package/dist/esm/src/core/dwn-constant.js +7 -7
  10. package/dist/esm/src/core/dwn-constant.js.map +1 -1
  11. package/dist/esm/src/core/dwn-error.js +1 -0
  12. package/dist/esm/src/core/dwn-error.js.map +1 -1
  13. package/dist/esm/src/core/grant-authorization.js +37 -52
  14. package/dist/esm/src/core/grant-authorization.js.map +1 -1
  15. package/dist/esm/src/core/message.js +85 -116
  16. package/dist/esm/src/core/message.js.map +1 -1
  17. package/dist/esm/src/core/messages-grant-authorization.js +63 -78
  18. package/dist/esm/src/core/messages-grant-authorization.js.map +1 -1
  19. package/dist/esm/src/core/protocol-authorization-action.js +266 -0
  20. package/dist/esm/src/core/protocol-authorization-action.js.map +1 -0
  21. package/dist/esm/src/core/protocol-authorization-validation.js +254 -0
  22. package/dist/esm/src/core/protocol-authorization-validation.js.map +1 -0
  23. package/dist/esm/src/core/protocol-authorization.js +122 -740
  24. package/dist/esm/src/core/protocol-authorization.js.map +1 -1
  25. package/dist/esm/src/core/protocols-grant-authorization.js +24 -38
  26. package/dist/esm/src/core/protocols-grant-authorization.js.map +1 -1
  27. package/dist/esm/src/core/record-chain.js +64 -0
  28. package/dist/esm/src/core/record-chain.js.map +1 -0
  29. package/dist/esm/src/core/records-grant-authorization.js +55 -72
  30. package/dist/esm/src/core/records-grant-authorization.js.map +1 -1
  31. package/dist/esm/src/core/resumable-task-manager.js +50 -65
  32. package/dist/esm/src/core/resumable-task-manager.js.map +1 -1
  33. package/dist/esm/src/core/tenant-gate.js +2 -13
  34. package/dist/esm/src/core/tenant-gate.js.map +1 -1
  35. package/dist/esm/src/dwn.js +69 -86
  36. package/dist/esm/src/dwn.js.map +1 -1
  37. package/dist/esm/src/event-stream/event-emitter-stream.js +17 -31
  38. package/dist/esm/src/event-stream/event-emitter-stream.js.map +1 -1
  39. package/dist/esm/src/handlers/messages-read.js +67 -77
  40. package/dist/esm/src/handlers/messages-read.js.map +1 -1
  41. package/dist/esm/src/handlers/messages-subscribe.js +51 -61
  42. package/dist/esm/src/handlers/messages-subscribe.js.map +1 -1
  43. package/dist/esm/src/handlers/messages-sync.js +75 -85
  44. package/dist/esm/src/handlers/messages-sync.js.map +1 -1
  45. package/dist/esm/src/handlers/protocols-configure.js +135 -155
  46. package/dist/esm/src/handlers/protocols-configure.js.map +1 -1
  47. package/dist/esm/src/handlers/protocols-query.js +52 -51
  48. package/dist/esm/src/handlers/protocols-query.js.map +1 -1
  49. package/dist/esm/src/handlers/records-count.js +96 -82
  50. package/dist/esm/src/handlers/records-count.js.map +1 -1
  51. package/dist/esm/src/handlers/records-delete.js +78 -88
  52. package/dist/esm/src/handlers/records-delete.js.map +1 -1
  53. package/dist/esm/src/handlers/records-query.js +116 -101
  54. package/dist/esm/src/handlers/records-query.js.map +1 -1
  55. package/dist/esm/src/handlers/records-read.js +124 -131
  56. package/dist/esm/src/handlers/records-read.js.map +1 -1
  57. package/dist/esm/src/handlers/records-subscribe.js +150 -103
  58. package/dist/esm/src/handlers/records-subscribe.js.map +1 -1
  59. package/dist/esm/src/handlers/records-write.js +250 -259
  60. package/dist/esm/src/handlers/records-write.js.map +1 -1
  61. package/dist/esm/src/interfaces/messages-read.js +24 -32
  62. package/dist/esm/src/interfaces/messages-read.js.map +1 -1
  63. package/dist/esm/src/interfaces/messages-subscribe.js +27 -41
  64. package/dist/esm/src/interfaces/messages-subscribe.js.map +1 -1
  65. package/dist/esm/src/interfaces/messages-sync.js +26 -40
  66. package/dist/esm/src/interfaces/messages-sync.js.map +1 -1
  67. package/dist/esm/src/interfaces/protocols-configure.js +63 -63
  68. package/dist/esm/src/interfaces/protocols-configure.js.map +1 -1
  69. package/dist/esm/src/interfaces/protocols-query.js +55 -68
  70. package/dist/esm/src/interfaces/protocols-query.js.map +1 -1
  71. package/dist/esm/src/interfaces/records-count.js +50 -66
  72. package/dist/esm/src/interfaces/records-count.js.map +1 -1
  73. package/dist/esm/src/interfaces/records-delete.js +45 -55
  74. package/dist/esm/src/interfaces/records-delete.js.map +1 -1
  75. package/dist/esm/src/interfaces/records-query.js +60 -76
  76. package/dist/esm/src/interfaces/records-query.js.map +1 -1
  77. package/dist/esm/src/interfaces/records-read.js +51 -67
  78. package/dist/esm/src/interfaces/records-read.js.map +1 -1
  79. package/dist/esm/src/interfaces/records-subscribe.js +52 -68
  80. package/dist/esm/src/interfaces/records-subscribe.js.map +1 -1
  81. package/dist/esm/src/interfaces/records-write-query.js +102 -0
  82. package/dist/esm/src/interfaces/records-write-query.js.map +1 -0
  83. package/dist/esm/src/interfaces/records-write-signing.js +92 -0
  84. package/dist/esm/src/interfaces/records-write-signing.js.map +1 -0
  85. package/dist/esm/src/interfaces/records-write.js +407 -602
  86. package/dist/esm/src/interfaces/records-write.js.map +1 -1
  87. package/dist/esm/src/jose/algorithms/signing/ed25519.js +10 -19
  88. package/dist/esm/src/jose/algorithms/signing/ed25519.js.map +1 -1
  89. package/dist/esm/src/jose/jws/general/builder.js +23 -35
  90. package/dist/esm/src/jose/jws/general/builder.js.map +1 -1
  91. package/dist/esm/src/jose/jws/general/verifier.js +56 -69
  92. package/dist/esm/src/jose/jws/general/verifier.js.map +1 -1
  93. package/dist/esm/src/protocols/permission-grant.js +44 -15
  94. package/dist/esm/src/protocols/permission-grant.js.map +1 -1
  95. package/dist/esm/src/protocols/permission-request.js +29 -15
  96. package/dist/esm/src/protocols/permission-request.js.map +1 -1
  97. package/dist/esm/src/protocols/permissions.js +216 -226
  98. package/dist/esm/src/protocols/permissions.js.map +1 -1
  99. package/dist/esm/src/smt/smt-store-level.js +42 -64
  100. package/dist/esm/src/smt/smt-store-level.js.map +1 -1
  101. package/dist/esm/src/smt/smt-store-memory.js +19 -45
  102. package/dist/esm/src/smt/smt-store-memory.js.map +1 -1
  103. package/dist/esm/src/smt/smt-utils.js +28 -45
  104. package/dist/esm/src/smt/smt-utils.js.map +1 -1
  105. package/dist/esm/src/smt/sparse-merkle-tree.js +426 -471
  106. package/dist/esm/src/smt/sparse-merkle-tree.js.map +1 -1
  107. package/dist/esm/src/state-index/state-index-level.js +115 -150
  108. package/dist/esm/src/state-index/state-index-level.js.map +1 -1
  109. package/dist/esm/src/store/blockstore-level.js +54 -156
  110. package/dist/esm/src/store/blockstore-level.js.map +1 -1
  111. package/dist/esm/src/store/blockstore-mock.js +48 -153
  112. package/dist/esm/src/store/blockstore-mock.js.map +1 -1
  113. package/dist/esm/src/store/data-store-level.js +59 -99
  114. package/dist/esm/src/store/data-store-level.js.map +1 -1
  115. package/dist/esm/src/store/index-level-compound.js +246 -0
  116. package/dist/esm/src/store/index-level-compound.js.map +1 -0
  117. package/dist/esm/src/store/index-level.js +295 -713
  118. package/dist/esm/src/store/index-level.js.map +1 -1
  119. package/dist/esm/src/store/level-wrapper.js +143 -244
  120. package/dist/esm/src/store/level-wrapper.js.map +1 -1
  121. package/dist/esm/src/store/message-store-level.js +71 -94
  122. package/dist/esm/src/store/message-store-level.js.map +1 -1
  123. package/dist/esm/src/store/resumable-task-store-level.js +62 -101
  124. package/dist/esm/src/store/resumable-task-store-level.js.map +1 -1
  125. package/dist/esm/src/store/storage-controller.js +129 -144
  126. package/dist/esm/src/store/storage-controller.js.map +1 -1
  127. package/dist/esm/src/utils/abort.js +8 -19
  128. package/dist/esm/src/utils/abort.js.map +1 -1
  129. package/dist/esm/src/utils/array.js +15 -49
  130. package/dist/esm/src/utils/array.js.map +1 -1
  131. package/dist/esm/src/utils/cid.js +29 -77
  132. package/dist/esm/src/utils/cid.js.map +1 -1
  133. package/dist/esm/src/utils/data-stream.js +37 -65
  134. package/dist/esm/src/utils/data-stream.js.map +1 -1
  135. package/dist/esm/src/utils/encryption.js +136 -162
  136. package/dist/esm/src/utils/encryption.js.map +1 -1
  137. package/dist/esm/src/utils/filter.js +1 -12
  138. package/dist/esm/src/utils/filter.js.map +1 -1
  139. package/dist/esm/src/utils/hd-key.js +45 -63
  140. package/dist/esm/src/utils/hd-key.js.map +1 -1
  141. package/dist/esm/src/utils/jws.js +9 -20
  142. package/dist/esm/src/utils/jws.js.map +1 -1
  143. package/dist/esm/src/utils/memory-cache.js +12 -23
  144. package/dist/esm/src/utils/memory-cache.js.map +1 -1
  145. package/dist/esm/src/utils/messages.js +9 -3
  146. package/dist/esm/src/utils/messages.js.map +1 -1
  147. package/dist/esm/src/utils/private-key-signer.js +9 -17
  148. package/dist/esm/src/utils/private-key-signer.js.map +1 -1
  149. package/dist/esm/src/utils/protocols.js +62 -70
  150. package/dist/esm/src/utils/protocols.js.map +1 -1
  151. package/dist/esm/src/utils/records.js +108 -140
  152. package/dist/esm/src/utils/records.js.map +1 -1
  153. package/dist/esm/src/utils/secp256k1.js +60 -96
  154. package/dist/esm/src/utils/secp256k1.js.map +1 -1
  155. package/dist/esm/src/utils/secp256r1.js +54 -71
  156. package/dist/esm/src/utils/secp256r1.js.map +1 -1
  157. package/dist/esm/src/utils/time.js +5 -18
  158. package/dist/esm/src/utils/time.js.map +1 -1
  159. package/dist/esm/src/utils/url.js +3 -3
  160. package/dist/esm/src/utils/url.js.map +1 -1
  161. package/dist/esm/tests/core/auth.spec.js +3 -12
  162. package/dist/esm/tests/core/auth.spec.js.map +1 -1
  163. package/dist/esm/tests/core/message.spec.js +50 -59
  164. package/dist/esm/tests/core/message.spec.js.map +1 -1
  165. package/dist/esm/tests/core/protocol-authorization.spec.js +9 -18
  166. package/dist/esm/tests/core/protocol-authorization.spec.js.map +1 -1
  167. package/dist/esm/tests/dwn.spec.js +45 -58
  168. package/dist/esm/tests/dwn.spec.js.map +1 -1
  169. package/dist/esm/tests/event-stream/event-emitter-stream.spec.js +24 -33
  170. package/dist/esm/tests/event-stream/event-emitter-stream.spec.js.map +1 -1
  171. package/dist/esm/tests/event-stream/event-stream.spec.js +46 -55
  172. package/dist/esm/tests/event-stream/event-stream.spec.js.map +1 -1
  173. package/dist/esm/tests/features/author-delegated-grant.spec.js +326 -343
  174. package/dist/esm/tests/features/author-delegated-grant.spec.js.map +1 -1
  175. package/dist/esm/tests/features/owner-delegated-grant.spec.js +153 -169
  176. package/dist/esm/tests/features/owner-delegated-grant.spec.js.map +1 -1
  177. package/dist/esm/tests/features/owner-signature.spec.js +67 -78
  178. package/dist/esm/tests/features/owner-signature.spec.js.map +1 -1
  179. package/dist/esm/tests/features/permissions.spec.js +446 -181
  180. package/dist/esm/tests/features/permissions.spec.js.map +1 -1
  181. package/dist/esm/tests/features/protocol-composition.spec.js +346 -356
  182. package/dist/esm/tests/features/protocol-composition.spec.js.map +1 -1
  183. package/dist/esm/tests/features/protocol-create-action.spec.js +42 -51
  184. package/dist/esm/tests/features/protocol-create-action.spec.js.map +1 -1
  185. package/dist/esm/tests/features/protocol-delete-action.spec.js +94 -103
  186. package/dist/esm/tests/features/protocol-delete-action.spec.js.map +1 -1
  187. package/dist/esm/tests/features/protocol-update-action.spec.js +105 -114
  188. package/dist/esm/tests/features/protocol-update-action.spec.js.map +1 -1
  189. package/dist/esm/tests/features/records-prune.spec.js +175 -191
  190. package/dist/esm/tests/features/records-prune.spec.js.map +1 -1
  191. package/dist/esm/tests/features/records-tags.spec.js +441 -460
  192. package/dist/esm/tests/features/records-tags.spec.js.map +1 -1
  193. package/dist/esm/tests/features/resumable-tasks.spec.js +82 -91
  194. package/dist/esm/tests/features/resumable-tasks.spec.js.map +1 -1
  195. package/dist/esm/tests/handlers/messages-read.spec.js +206 -207
  196. package/dist/esm/tests/handlers/messages-read.spec.js.map +1 -1
  197. package/dist/esm/tests/handlers/messages-subscribe.spec.js +145 -154
  198. package/dist/esm/tests/handlers/messages-subscribe.spec.js.map +1 -1
  199. package/dist/esm/tests/handlers/messages-sync.spec.js +174 -183
  200. package/dist/esm/tests/handlers/messages-sync.spec.js.map +1 -1
  201. package/dist/esm/tests/handlers/protocols-configure.spec.js +244 -238
  202. package/dist/esm/tests/handlers/protocols-configure.spec.js.map +1 -1
  203. package/dist/esm/tests/handlers/protocols-query.spec.js +156 -169
  204. package/dist/esm/tests/handlers/protocols-query.spec.js.map +1 -1
  205. package/dist/esm/tests/handlers/records-count.spec.js +93 -102
  206. package/dist/esm/tests/handlers/records-count.spec.js.map +1 -1
  207. package/dist/esm/tests/handlers/records-delete.spec.js +252 -264
  208. package/dist/esm/tests/handlers/records-delete.spec.js.map +1 -1
  209. package/dist/esm/tests/handlers/records-query.spec.js +917 -988
  210. package/dist/esm/tests/handlers/records-query.spec.js.map +1 -1
  211. package/dist/esm/tests/handlers/records-read.spec.js +553 -568
  212. package/dist/esm/tests/handlers/records-read.spec.js.map +1 -1
  213. package/dist/esm/tests/handlers/records-subscribe.spec.js +269 -278
  214. package/dist/esm/tests/handlers/records-subscribe.spec.js.map +1 -1
  215. package/dist/esm/tests/handlers/records-write.spec.js +1057 -1082
  216. package/dist/esm/tests/handlers/records-write.spec.js.map +1 -1
  217. package/dist/esm/tests/interfaces/messages-get.spec.js +39 -48
  218. package/dist/esm/tests/interfaces/messages-get.spec.js.map +1 -1
  219. package/dist/esm/tests/interfaces/messages-subscribe.spec.js +4 -13
  220. package/dist/esm/tests/interfaces/messages-subscribe.spec.js.map +1 -1
  221. package/dist/esm/tests/interfaces/protocols-configure.spec.js +212 -88
  222. package/dist/esm/tests/interfaces/protocols-configure.spec.js.map +1 -1
  223. package/dist/esm/tests/interfaces/protocols-query.spec.js +8 -17
  224. package/dist/esm/tests/interfaces/protocols-query.spec.js.map +1 -1
  225. package/dist/esm/tests/interfaces/records-delete.spec.js +8 -17
  226. package/dist/esm/tests/interfaces/records-delete.spec.js.map +1 -1
  227. package/dist/esm/tests/interfaces/records-query.spec.js +20 -29
  228. package/dist/esm/tests/interfaces/records-query.spec.js.map +1 -1
  229. package/dist/esm/tests/interfaces/records-read.spec.js +42 -51
  230. package/dist/esm/tests/interfaces/records-read.spec.js.map +1 -1
  231. package/dist/esm/tests/interfaces/records-subscribe.spec.js +16 -25
  232. package/dist/esm/tests/interfaces/records-subscribe.spec.js.map +1 -1
  233. package/dist/esm/tests/interfaces/records-write.spec.js +152 -165
  234. package/dist/esm/tests/interfaces/records-write.spec.js.map +1 -1
  235. package/dist/esm/tests/jose/jws/general.spec.js +36 -45
  236. package/dist/esm/tests/jose/jws/general.spec.js.map +1 -1
  237. package/dist/esm/tests/protocols/permission-grant.spec.js +44 -50
  238. package/dist/esm/tests/protocols/permission-grant.spec.js.map +1 -1
  239. package/dist/esm/tests/protocols/permission-request.spec.js +23 -32
  240. package/dist/esm/tests/protocols/permission-request.spec.js.map +1 -1
  241. package/dist/esm/tests/protocols/permissions.spec.js +49 -55
  242. package/dist/esm/tests/protocols/permissions.spec.js.map +1 -1
  243. package/dist/esm/tests/scenarios/aggregator.spec.js +124 -135
  244. package/dist/esm/tests/scenarios/aggregator.spec.js.map +1 -1
  245. package/dist/esm/tests/scenarios/deleted-record.spec.js +23 -32
  246. package/dist/esm/tests/scenarios/deleted-record.spec.js.map +1 -1
  247. package/dist/esm/tests/scenarios/end-to-end-tests.spec.js +52 -61
  248. package/dist/esm/tests/scenarios/end-to-end-tests.spec.js.map +1 -1
  249. package/dist/esm/tests/scenarios/nested-roles.spec.js +63 -73
  250. package/dist/esm/tests/scenarios/nested-roles.spec.js.map +1 -1
  251. package/dist/esm/tests/scenarios/subscriptions.spec.js +377 -333
  252. package/dist/esm/tests/scenarios/subscriptions.spec.js.map +1 -1
  253. package/dist/esm/tests/smt/smt-store-level.spec.js +76 -87
  254. package/dist/esm/tests/smt/smt-store-level.spec.js.map +1 -1
  255. package/dist/esm/tests/smt/sparse-merkle-tree.spec.js +344 -353
  256. package/dist/esm/tests/smt/sparse-merkle-tree.spec.js.map +1 -1
  257. package/dist/esm/tests/state-index/state-index-level.spec.js +117 -126
  258. package/dist/esm/tests/state-index/state-index-level.spec.js.map +1 -1
  259. package/dist/esm/tests/store/blockstore-level.spec.js +44 -99
  260. package/dist/esm/tests/store/blockstore-level.spec.js.map +1 -1
  261. package/dist/esm/tests/store/blockstore-mock.spec.js +40 -120
  262. package/dist/esm/tests/store/blockstore-mock.spec.js.map +1 -1
  263. package/dist/esm/tests/store/data-store-level.spec.js +86 -95
  264. package/dist/esm/tests/store/data-store-level.spec.js.map +1 -1
  265. package/dist/esm/tests/store/index-level.spec.js +404 -414
  266. package/dist/esm/tests/store/index-level.spec.js.map +1 -1
  267. package/dist/esm/tests/store/message-store-level.spec.js +13 -22
  268. package/dist/esm/tests/store/message-store-level.spec.js.map +1 -1
  269. package/dist/esm/tests/store/message-store.spec.js +229 -238
  270. package/dist/esm/tests/store/message-store.spec.js.map +1 -1
  271. package/dist/esm/tests/test-event-stream.js +3 -3
  272. package/dist/esm/tests/test-event-stream.js.map +1 -1
  273. package/dist/esm/tests/test-stores.js +16 -13
  274. package/dist/esm/tests/test-stores.js.map +1 -1
  275. package/dist/esm/tests/test-suite.js +2 -11
  276. package/dist/esm/tests/test-suite.js.map +1 -1
  277. package/dist/esm/tests/utils/cid.spec.js +24 -33
  278. package/dist/esm/tests/utils/cid.spec.js.map +1 -1
  279. package/dist/esm/tests/utils/data-stream.spec.js +48 -57
  280. package/dist/esm/tests/utils/data-stream.spec.js.map +1 -1
  281. package/dist/esm/tests/utils/encryption-callbacks.spec.js +45 -54
  282. package/dist/esm/tests/utils/encryption-callbacks.spec.js.map +1 -1
  283. package/dist/esm/tests/utils/encryption.spec.js +291 -44
  284. package/dist/esm/tests/utils/encryption.spec.js.map +1 -1
  285. package/dist/esm/tests/utils/filters.spec.js +46 -55
  286. package/dist/esm/tests/utils/filters.spec.js.map +1 -1
  287. package/dist/esm/tests/utils/hd-key.spec.js +10 -19
  288. package/dist/esm/tests/utils/hd-key.spec.js.map +1 -1
  289. package/dist/esm/tests/utils/jws.spec.js +3 -12
  290. package/dist/esm/tests/utils/jws.spec.js.map +1 -1
  291. package/dist/esm/tests/utils/memory-cache.spec.js +9 -18
  292. package/dist/esm/tests/utils/memory-cache.spec.js.map +1 -1
  293. package/dist/esm/tests/utils/messages.spec.js +6 -15
  294. package/dist/esm/tests/utils/messages.spec.js.map +1 -1
  295. package/dist/esm/tests/utils/poller.js +22 -33
  296. package/dist/esm/tests/utils/poller.js.map +1 -1
  297. package/dist/esm/tests/utils/private-key-signer.spec.js +15 -24
  298. package/dist/esm/tests/utils/private-key-signer.spec.js.map +1 -1
  299. package/dist/esm/tests/utils/records.spec.js +10 -19
  300. package/dist/esm/tests/utils/records.spec.js.map +1 -1
  301. package/dist/esm/tests/utils/secp256k1.spec.js +16 -25
  302. package/dist/esm/tests/utils/secp256k1.spec.js.map +1 -1
  303. package/dist/esm/tests/utils/secp256r1.spec.js +18 -27
  304. package/dist/esm/tests/utils/secp256r1.spec.js.map +1 -1
  305. package/dist/esm/tests/utils/test-data-generator.js +414 -468
  306. package/dist/esm/tests/utils/test-data-generator.js.map +1 -1
  307. package/dist/esm/tests/validation/json-schemas/definitions.spec.js +2 -11
  308. package/dist/esm/tests/validation/json-schemas/definitions.spec.js.map +1 -1
  309. package/dist/esm/tests/validation/json-schemas/jwk/general-jwk.spec.js +4 -13
  310. package/dist/esm/tests/validation/json-schemas/jwk/general-jwk.spec.js.map +1 -1
  311. package/dist/esm/tests/validation/json-schemas/jwk/public-jwk.spec.js +8 -17
  312. package/dist/esm/tests/validation/json-schemas/jwk/public-jwk.spec.js.map +1 -1
  313. package/dist/esm/tests/validation/json-schemas/jwk-verification-method.spec.js +3 -12
  314. package/dist/esm/tests/validation/json-schemas/jwk-verification-method.spec.js.map +1 -1
  315. package/dist/esm/tests/validation/json-schemas/protocols/protocols-configure.spec.js +4 -13
  316. package/dist/esm/tests/validation/json-schemas/protocols/protocols-configure.spec.js.map +1 -1
  317. package/dist/esm/tests/validation/json-schemas/records/records-query.spec.js +2 -11
  318. package/dist/esm/tests/validation/json-schemas/records/records-query.spec.js.map +1 -1
  319. package/dist/esm/tests/validation/json-schemas/records/records-read.spec.js +2 -11
  320. package/dist/esm/tests/validation/json-schemas/records/records-read.spec.js.map +1 -1
  321. package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js +7 -16
  322. package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js.map +1 -1
  323. package/dist/types/src/core/protocol-authorization-action.d.ts +42 -0
  324. package/dist/types/src/core/protocol-authorization-action.d.ts.map +1 -0
  325. package/dist/types/src/core/protocol-authorization-validation.d.ts +60 -0
  326. package/dist/types/src/core/protocol-authorization-validation.d.ts.map +1 -0
  327. package/dist/types/src/core/protocol-authorization.d.ts +10 -100
  328. package/dist/types/src/core/protocol-authorization.d.ts.map +1 -1
  329. package/dist/types/src/core/record-chain.d.ts +24 -0
  330. package/dist/types/src/core/record-chain.d.ts.map +1 -0
  331. package/dist/types/src/handlers/records-write.d.ts +2 -1
  332. package/dist/types/src/handlers/records-write.d.ts.map +1 -1
  333. package/dist/types/src/interfaces/protocols-configure.d.ts.map +1 -1
  334. package/dist/types/src/interfaces/records-write-query.d.ts +33 -0
  335. package/dist/types/src/interfaces/records-write-query.d.ts.map +1 -0
  336. package/dist/types/src/interfaces/records-write-signing.d.ts +35 -0
  337. package/dist/types/src/interfaces/records-write-signing.d.ts.map +1 -0
  338. package/dist/types/src/interfaces/records-write.d.ts +10 -44
  339. package/dist/types/src/interfaces/records-write.d.ts.map +1 -1
  340. package/dist/types/src/store/index-level-compound.d.ts +70 -0
  341. package/dist/types/src/store/index-level-compound.d.ts.map +1 -0
  342. package/dist/types/src/store/index-level.d.ts +0 -58
  343. package/dist/types/src/store/index-level.d.ts.map +1 -1
  344. package/dist/types/src/utils/protocols.d.ts +5 -0
  345. package/dist/types/src/utils/protocols.d.ts.map +1 -1
  346. package/dist/types/src/utils/records.d.ts +3 -1
  347. package/dist/types/src/utils/records.d.ts.map +1 -1
  348. package/dist/types/tests/features/permissions.spec.d.ts.map +1 -1
  349. package/package.json +3 -3
  350. package/src/core/protocol-authorization-action.ts +377 -0
  351. package/src/core/protocol-authorization-validation.ts +391 -0
  352. package/src/core/protocol-authorization.ts +60 -849
  353. package/src/core/record-chain.ts +99 -0
  354. package/src/handlers/records-read.ts +1 -1
  355. package/src/handlers/records-write.ts +37 -21
  356. package/src/interfaces/protocols-configure.ts +33 -5
  357. package/src/interfaces/records-write-query.ts +139 -0
  358. package/src/interfaces/records-write-signing.ts +143 -0
  359. package/src/interfaces/records-write.ts +49 -221
  360. package/src/store/index-level-compound.ts +324 -0
  361. package/src/store/index-level.ts +24 -306
  362. package/src/utils/protocols.ts +8 -0
  363. package/src/utils/records.ts +9 -15
@@ -1,72 +1,41 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- var __asyncValues = (this && this.__asyncValues) || function (o) {
11
- if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
12
- var m = o[Symbol.asyncIterator], i;
13
- return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
14
- function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
15
- function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
16
- };
17
- var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
18
- var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
19
- if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
20
- var g = generator.apply(thisArg, _arguments || []), i, q = [];
21
- return i = {}, verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
22
- function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
23
- function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
24
- function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
25
- function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
26
- function fulfill(value) { resume("next", value); }
27
- function reject(value) { resume("throw", value); }
28
- function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
29
- };
30
1
  import { isEmptyObject } from '../utils/object.js';
31
2
  import { lexicographicalCompare } from '../utils/string.js';
32
3
  import { SortDirection } from '../types/query-types.js';
4
+ import { countWithCompoundIndex, createCompoundIndexDeleteOperation, createCompoundIndexPutOperation, queryWithCompoundIndex, selectCompoundIndex, } from './index-level-compound.js';
33
5
  import { createLevelDatabase, LevelWrapper } from './level-wrapper.js';
34
6
  import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
35
7
  import { FilterSelector, FilterUtility } from '../utils/filter.js';
36
8
  const INDEX_SUBLEVEL_NAME = 'index';
37
- /** Separator between compound key segments (higher than \x00 so prefix scans work correctly). */
38
- const COMPOUND_SEGMENT_SEPARATOR = '\x01';
39
9
  /**
40
10
  * A LevelDB implementation for indexing the messages and events stored in the DWN.
41
11
  */
42
12
  export class IndexLevel {
13
+ db;
14
+ config;
15
+ _compoundIndexes;
43
16
  constructor(config) {
44
- var _a;
45
- this.config = Object.assign({ createLevelDatabase }, config);
46
- this._compoundIndexes = (_a = config.compoundIndexes) !== null && _a !== void 0 ? _a : [];
17
+ this.config = {
18
+ createLevelDatabase,
19
+ ...config,
20
+ };
21
+ this._compoundIndexes = config.compoundIndexes ?? [];
47
22
  this.db = new LevelWrapper({
48
23
  location: this.config.location,
49
24
  createLevelDatabase: this.config.createLevelDatabase,
50
25
  keyEncoding: 'utf8'
51
26
  });
52
27
  }
53
- open() {
54
- return __awaiter(this, void 0, void 0, function* () {
55
- yield this.db.open();
56
- });
28
+ async open() {
29
+ await this.db.open();
57
30
  }
58
- close() {
59
- return __awaiter(this, void 0, void 0, function* () {
60
- yield this.db.close();
61
- });
31
+ async close() {
32
+ await this.db.close();
62
33
  }
63
34
  /**
64
35
  * deletes everything in the underlying index db.
65
36
  */
66
- clear() {
67
- return __awaiter(this, void 0, void 0, function* () {
68
- yield this.db.clear();
69
- });
37
+ async clear() {
38
+ await this.db.clear();
70
39
  }
71
40
  /**
72
41
  * Put an item into the index using information that will allow it to be queried for.
@@ -76,132 +45,120 @@ export class IndexLevel {
76
45
  * @param indexes - (key-value pairs) to be included as part of indexing this item. Must include at least one indexing property.
77
46
  * @param options IndexLevelOptions that include an AbortSignal.
78
47
  */
79
- put(tenant, messageCid, indexes, options) {
80
- return __awaiter(this, void 0, void 0, function* () {
81
- // ensure we have something valid to index
82
- if (isEmptyObject(indexes)) {
83
- throw new DwnError(DwnErrorCode.IndexMissingIndexableProperty, 'Index must include at least one valid indexable property');
84
- }
85
- const item = { messageCid, indexes };
86
- const opCreationPromises = [];
87
- // create an index entry for each property index
88
- // these indexes are all sortable lexicographically.
89
- for (const indexName in indexes) {
90
- const indexValue = indexes[indexName];
91
- if (Array.isArray(indexValue)) {
92
- for (const indexValueItem of indexValue) {
93
- const partitionOperationPromise = this.createPutIndexedItemOperation(tenant, item, indexName, indexValueItem);
94
- opCreationPromises.push(partitionOperationPromise);
95
- }
96
- }
97
- else {
98
- const partitionOperationPromise = this.createPutIndexedItemOperation(tenant, item, indexName, indexValue);
48
+ async put(tenant, messageCid, indexes, options) {
49
+ // ensure we have something valid to index
50
+ if (isEmptyObject(indexes)) {
51
+ throw new DwnError(DwnErrorCode.IndexMissingIndexableProperty, 'Index must include at least one valid indexable property');
52
+ }
53
+ const item = { messageCid, indexes };
54
+ const opCreationPromises = [];
55
+ // create an index entry for each property index
56
+ // these indexes are all sortable lexicographically.
57
+ for (const indexName in indexes) {
58
+ const indexValue = indexes[indexName];
59
+ if (Array.isArray(indexValue)) {
60
+ for (const indexValueItem of indexValue) {
61
+ const partitionOperationPromise = this.createPutIndexedItemOperation(tenant, item, indexName, indexValueItem);
99
62
  opCreationPromises.push(partitionOperationPromise);
100
63
  }
101
64
  }
102
- // create compound index entries for any registered compound indexes whose properties are all present in the indexes.
103
- for (const compoundIndex of this._compoundIndexes) {
104
- const compoundOp = this.createCompoundIndexPutOperation(tenant, item, compoundIndex);
105
- if (compoundOp !== undefined) {
106
- opCreationPromises.push(compoundOp);
107
- }
65
+ else {
66
+ const partitionOperationPromise = this.createPutIndexedItemOperation(tenant, item, indexName, indexValue);
67
+ opCreationPromises.push(partitionOperationPromise);
108
68
  }
109
- // create a reverse lookup for the sortedIndex values. This is used during deletion and cursor starting point lookup.
110
- const partitionOperationPromise = this.createOperationForIndexesLookupPartition(tenant, { type: 'put', key: messageCid, value: JSON.stringify(indexes) });
111
- opCreationPromises.push(partitionOperationPromise);
112
- const indexOps = yield Promise.all(opCreationPromises);
113
- const tenantPartition = yield this.db.partition(tenant);
114
- yield tenantPartition.batch(indexOps, options);
115
- });
69
+ }
70
+ // create compound index entries for any registered compound indexes whose properties are all present in the indexes.
71
+ for (const compoundIndex of this._compoundIndexes) {
72
+ const compoundOp = createCompoundIndexPutOperation(this.db, tenant, item, compoundIndex, IndexLevel.encodeValue, IndexLevel.delimiter);
73
+ if (compoundOp !== undefined) {
74
+ opCreationPromises.push(compoundOp);
75
+ }
76
+ }
77
+ // create a reverse lookup for the sortedIndex values. This is used during deletion and cursor starting point lookup.
78
+ const partitionOperationPromise = this.createOperationForIndexesLookupPartition(tenant, { type: 'put', key: messageCid, value: JSON.stringify(indexes) });
79
+ opCreationPromises.push(partitionOperationPromise);
80
+ const indexOps = await Promise.all(opCreationPromises);
81
+ const tenantPartition = await this.db.partition(tenant);
82
+ await tenantPartition.batch(indexOps, options);
116
83
  }
117
84
  /**
118
85
  * Deletes all of the index data associated with the item.
119
86
  */
120
- delete(tenant, messageCid, options) {
121
- return __awaiter(this, void 0, void 0, function* () {
122
- const opCreationPromises = [];
123
- const indexes = yield this.getIndexes(tenant, messageCid);
124
- if (indexes === undefined) {
125
- // invalid messageCid
126
- return;
127
- }
128
- // delete the reverse lookup
129
- const partitionOperationPromise = this.createOperationForIndexesLookupPartition(tenant, { type: 'del', key: messageCid });
130
- opCreationPromises.push(partitionOperationPromise);
131
- // delete the keys for each index
132
- for (const indexName in indexes) {
133
- const indexValue = indexes[indexName];
134
- if (Array.isArray(indexValue)) {
135
- for (const indexValueItem of indexValue) {
136
- const partitionOperationPromise = this.createDeleteIndexedItemOperation(tenant, messageCid, indexName, indexValueItem);
137
- opCreationPromises.push(partitionOperationPromise);
138
- }
139
- }
140
- else {
141
- const partitionOperationPromise = this.createDeleteIndexedItemOperation(tenant, messageCid, indexName, indexValue);
87
+ async delete(tenant, messageCid, options) {
88
+ const opCreationPromises = [];
89
+ const indexes = await this.getIndexes(tenant, messageCid);
90
+ if (indexes === undefined) {
91
+ // invalid messageCid
92
+ return;
93
+ }
94
+ // delete the reverse lookup
95
+ const partitionOperationPromise = this.createOperationForIndexesLookupPartition(tenant, { type: 'del', key: messageCid });
96
+ opCreationPromises.push(partitionOperationPromise);
97
+ // delete the keys for each index
98
+ for (const indexName in indexes) {
99
+ const indexValue = indexes[indexName];
100
+ if (Array.isArray(indexValue)) {
101
+ for (const indexValueItem of indexValue) {
102
+ const partitionOperationPromise = this.createDeleteIndexedItemOperation(tenant, messageCid, indexName, indexValueItem);
142
103
  opCreationPromises.push(partitionOperationPromise);
143
104
  }
144
105
  }
145
- // delete compound index entries
146
- for (const compoundIndex of this._compoundIndexes) {
147
- const compoundOp = this.createCompoundIndexDeleteOperation(tenant, messageCid, indexes, compoundIndex);
148
- if (compoundOp !== undefined) {
149
- opCreationPromises.push(compoundOp);
150
- }
106
+ else {
107
+ const partitionOperationPromise = this.createDeleteIndexedItemOperation(tenant, messageCid, indexName, indexValue);
108
+ opCreationPromises.push(partitionOperationPromise);
151
109
  }
152
- const indexOps = yield Promise.all(opCreationPromises);
153
- const tenantPartition = yield this.db.partition(tenant);
154
- yield tenantPartition.batch(indexOps, options);
155
- });
110
+ }
111
+ // delete compound index entries
112
+ for (const compoundIndex of this._compoundIndexes) {
113
+ const compoundOp = createCompoundIndexDeleteOperation(this.db, tenant, messageCid, indexes, compoundIndex, IndexLevel.encodeValue, IndexLevel.delimiter);
114
+ if (compoundOp !== undefined) {
115
+ opCreationPromises.push(compoundOp);
116
+ }
117
+ }
118
+ const indexOps = await Promise.all(opCreationPromises);
119
+ const tenantPartition = await this.db.partition(tenant);
120
+ await tenantPartition.batch(indexOps, options);
156
121
  }
157
122
  /**
158
123
  * Creates an IndexLevel `put` operation for indexing an item, creating a partition by `tenant` and by `indexName`
159
124
  */
160
- createPutIndexedItemOperation(tenant, item, indexName, indexValue) {
161
- return __awaiter(this, void 0, void 0, function* () {
162
- const { messageCid } = item;
163
- // The key is the indexValue followed by the messageCid as a tie-breaker.
164
- // for example if the property is messageTimestamp the key would look like:
165
- // '"2023-05-25T18:23:29.425008Z"\u0000bafyreigs3em7lrclhntzhgvkrf75j2muk6e7ypq3lrw3ffgcpyazyw6pry'
166
- const key = IndexLevel.keySegmentJoin(IndexLevel.encodeValue(indexValue), messageCid);
167
- return this.createOperationForIndexPartition(tenant, indexName, { type: 'put', key, value: JSON.stringify(item) });
168
- });
125
+ async createPutIndexedItemOperation(tenant, item, indexName, indexValue) {
126
+ const { messageCid } = item;
127
+ // The key is the indexValue followed by the messageCid as a tie-breaker.
128
+ // for example if the property is messageTimestamp the key would look like:
129
+ // '"2023-05-25T18:23:29.425008Z"\u0000bafyreigs3em7lrclhntzhgvkrf75j2muk6e7ypq3lrw3ffgcpyazyw6pry'
130
+ const key = IndexLevel.keySegmentJoin(IndexLevel.encodeValue(indexValue), messageCid);
131
+ return this.createOperationForIndexPartition(tenant, indexName, { type: 'put', key, value: JSON.stringify(item) });
169
132
  }
170
133
  /**
171
134
  * Creates an IndexLevel `del` operation for deleting an item, creating a partition by `tenant` and by `indexName`
172
135
  */
173
- createDeleteIndexedItemOperation(tenant, messageCid, indexName, indexValue) {
174
- return __awaiter(this, void 0, void 0, function* () {
175
- // The key is the indexValue followed by the messageCid as a tie-breaker.
176
- // for example if the property is messageTimestamp the key would look like:
177
- // '"2023-05-25T18:23:29.425008Z"\u0000bafyreigs3em7lrclhntzhgvkrf75j2muk6e7ypq3lrw3ffgcpyazyw6pry'
178
- const key = IndexLevel.keySegmentJoin(IndexLevel.encodeValue(indexValue), messageCid);
179
- return this.createOperationForIndexPartition(tenant, indexName, { type: 'del', key });
180
- });
136
+ async createDeleteIndexedItemOperation(tenant, messageCid, indexName, indexValue) {
137
+ // The key is the indexValue followed by the messageCid as a tie-breaker.
138
+ // for example if the property is messageTimestamp the key would look like:
139
+ // '"2023-05-25T18:23:29.425008Z"\u0000bafyreigs3em7lrclhntzhgvkrf75j2muk6e7ypq3lrw3ffgcpyazyw6pry'
140
+ const key = IndexLevel.keySegmentJoin(IndexLevel.encodeValue(indexValue), messageCid);
141
+ return this.createOperationForIndexPartition(tenant, indexName, { type: 'del', key });
181
142
  }
182
143
  /**
183
144
  * Wraps the given operation as an operation for the specified index partition.
184
145
  */
185
- createOperationForIndexPartition(tenant, indexName, operation) {
186
- return __awaiter(this, void 0, void 0, function* () {
187
- // we write the index entry into a sublevel-partition of tenantPartition.
188
- // putting each index entry within a sublevel allows the levelDB system to calculate a gt minKey and lt maxKey for each of the properties
189
- // this prevents them from clashing, especially when iterating in reverse without iterating through other properties.
190
- const tenantPartition = yield this.db.partition(tenant);
191
- const indexPartitionName = IndexLevel.getIndexPartitionName(indexName);
192
- const partitionOperation = tenantPartition.createPartitionOperation(indexPartitionName, operation);
193
- return partitionOperation;
194
- });
146
+ async createOperationForIndexPartition(tenant, indexName, operation) {
147
+ // we write the index entry into a sublevel-partition of tenantPartition.
148
+ // putting each index entry within a sublevel allows the levelDB system to calculate a gt minKey and lt maxKey for each of the properties
149
+ // this prevents them from clashing, especially when iterating in reverse without iterating through other properties.
150
+ const tenantPartition = await this.db.partition(tenant);
151
+ const indexPartitionName = IndexLevel.getIndexPartitionName(indexName);
152
+ const partitionOperation = tenantPartition.createPartitionOperation(indexPartitionName, operation);
153
+ return partitionOperation;
195
154
  }
196
155
  /**
197
156
  * Wraps the given operation as an operation for the messageCid to indexes lookup partition.
198
157
  */
199
- createOperationForIndexesLookupPartition(tenant, operation) {
200
- return __awaiter(this, void 0, void 0, function* () {
201
- const tenantPartition = yield this.db.partition(tenant);
202
- const partitionOperation = tenantPartition.createPartitionOperation(INDEX_SUBLEVEL_NAME, operation);
203
- return partitionOperation;
204
- });
158
+ async createOperationForIndexesLookupPartition(tenant, operation) {
159
+ const tenantPartition = await this.db.partition(tenant);
160
+ const partitionOperation = tenantPartition.createPartitionOperation(INDEX_SUBLEVEL_NAME, operation);
161
+ return partitionOperation;
205
162
  }
206
163
  static getIndexPartitionName(indexName) {
207
164
  // we create index partition names in __${indexName}__ wrapping so they do not clash with other sublevels that are created for other purposes.
@@ -210,19 +167,15 @@ export class IndexLevel {
210
167
  /**
211
168
  * Gets the index partition of the given indexName.
212
169
  */
213
- getIndexPartition(tenant, indexName) {
214
- return __awaiter(this, void 0, void 0, function* () {
215
- const indexPartitionName = IndexLevel.getIndexPartitionName(indexName);
216
- return (yield this.db.partition(tenant)).partition(indexPartitionName);
217
- });
170
+ async getIndexPartition(tenant, indexName) {
171
+ const indexPartitionName = IndexLevel.getIndexPartitionName(indexName);
172
+ return (await this.db.partition(tenant)).partition(indexPartitionName);
218
173
  }
219
174
  /**
220
175
  * Gets the messageCid to indexes lookup partition.
221
176
  */
222
- getIndexesLookupPartition(tenant) {
223
- return __awaiter(this, void 0, void 0, function* () {
224
- return (yield this.db.partition(tenant)).partition(INDEX_SUBLEVEL_NAME);
225
- });
177
+ async getIndexesLookupPartition(tenant) {
178
+ return (await this.db.partition(tenant)).partition(INDEX_SUBLEVEL_NAME);
226
179
  }
227
180
  /**
228
181
  * Queries the index for items that match the filters. If no filters are provided, all items are returned.
@@ -238,22 +191,20 @@ export class IndexLevel {
238
191
  * @param options IndexLevelOptions that include an AbortSignal.
239
192
  * @returns {IndexedItem[]} an array of `IndexedItem` that match the given filters.
240
193
  */
241
- query(tenant, filters, queryOptions, options) {
242
- return __awaiter(this, void 0, void 0, function* () {
243
- // Strategy 1: try compound index for single-filter queries
244
- if (filters.length === 1 && !isEmptyObject(filters[0])) {
245
- const compoundResult = this.selectCompoundIndex(filters[0], queryOptions);
246
- if (compoundResult !== undefined) {
247
- return this.queryWithCompoundIndex(tenant, filters[0], queryOptions, compoundResult, options);
248
- }
249
- }
250
- // Strategy 2: in-memory paging for concise filters
251
- if (IndexLevel.shouldQueryWithInMemoryPaging(filters, queryOptions)) {
252
- return this.queryWithInMemoryPaging(tenant, filters, queryOptions, options);
194
+ async query(tenant, filters, queryOptions, options) {
195
+ // Strategy 1: try compound index for single-filter queries
196
+ if (filters.length === 1 && !isEmptyObject(filters[0])) {
197
+ const compoundResult = selectCompoundIndex(filters[0], queryOptions, this._compoundIndexes);
198
+ if (compoundResult !== undefined) {
199
+ return queryWithCompoundIndex(this.db, tenant, filters[0], queryOptions, compoundResult, IndexLevel.encodeValue, IndexLevel.delimiter, this.queryWithIteratorPaging.bind(this), options);
253
200
  }
254
- // Strategy 3: iterator paging (default)
255
- return this.queryWithIteratorPaging(tenant, filters, queryOptions, options);
256
- });
201
+ }
202
+ // Strategy 2: in-memory paging for concise filters
203
+ if (IndexLevel.shouldQueryWithInMemoryPaging(filters, queryOptions)) {
204
+ return this.queryWithInMemoryPaging(tenant, filters, queryOptions, options);
205
+ }
206
+ // Strategy 3: iterator paging (default)
207
+ return this.queryWithIteratorPaging(tenant, filters, queryOptions, options);
257
208
  }
258
209
  /**
259
210
  * Counts the number of items that match the given filters without loading full records.
@@ -261,94 +212,62 @@ export class IndexLevel {
261
212
  * When a compound index covers the query, counting is a simple key iteration without value deserialization.
262
213
  * Otherwise, falls back to counting via the existing query strategies.
263
214
  */
264
- count(tenant, filters, queryOptions, options) {
265
- return __awaiter(this, void 0, void 0, function* () {
266
- // try compound index for single-filter queries
267
- if (filters.length === 1 && !isEmptyObject(filters[0])) {
268
- const compoundResult = this.selectCompoundIndex(filters[0], Object.assign({}, queryOptions));
269
- if (compoundResult !== undefined) {
270
- return this.countWithCompoundIndex(tenant, filters[0], compoundResult, options);
271
- }
215
+ async count(tenant, filters, queryOptions, options) {
216
+ // try compound index for single-filter queries
217
+ if (filters.length === 1 && !isEmptyObject(filters[0])) {
218
+ const compoundResult = selectCompoundIndex(filters[0], { ...queryOptions }, this._compoundIndexes);
219
+ if (compoundResult !== undefined) {
220
+ return countWithCompoundIndex(this.db, tenant, filters[0], compoundResult, IndexLevel.encodeValue, this.query.bind(this), options);
272
221
  }
273
- // fallback: run a full query without limit and count the results
274
- const results = yield this.query(tenant, filters, Object.assign({}, queryOptions), options);
275
- return results.length;
276
- });
222
+ }
223
+ // fallback: run a full query without limit and count the results
224
+ const results = await this.query(tenant, filters, { ...queryOptions }, options);
225
+ return results.length;
277
226
  }
278
227
  /**
279
228
  * Queries the sort property index for items that match the filters. If no filters are provided, all items are returned.
280
229
  * This query is a linear iterator over the sorted index, checking each item for a match.
281
230
  * If a cursor is provided it starts the iteration from the cursor point.
282
231
  */
283
- queryWithIteratorPaging(tenant, filters, queryOptions, options) {
284
- return __awaiter(this, void 0, void 0, function* () {
285
- var _a, e_1, _b, _c;
286
- const { cursor: queryCursor, limit } = queryOptions;
287
- // if there is a cursor we fetch the starting key given the sort property, otherwise we start from the beginning of the index.
288
- const startKey = queryCursor ? this.createStartingKeyFromCursor(queryCursor) : '';
289
- const matches = [];
290
- try {
291
- for (var _d = true, _e = __asyncValues(this.getIndexIterator(tenant, startKey, queryOptions, options)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
292
- _c = _f.value;
293
- _d = false;
294
- const item = _c;
295
- if (limit !== undefined && limit === matches.length) {
296
- break;
297
- }
298
- const { indexes } = item;
299
- if (FilterUtility.matchAnyFilter(indexes, filters)) {
300
- matches.push(item);
301
- }
302
- }
232
+ async queryWithIteratorPaging(tenant, filters, queryOptions, options) {
233
+ const { cursor: queryCursor, limit } = queryOptions;
234
+ // if there is a cursor we fetch the starting key given the sort property, otherwise we start from the beginning of the index.
235
+ const startKey = queryCursor ? this.createStartingKeyFromCursor(queryCursor) : '';
236
+ const matches = [];
237
+ for await (const item of this.getIndexIterator(tenant, startKey, queryOptions, options)) {
238
+ if (limit !== undefined && limit === matches.length) {
239
+ break;
303
240
  }
304
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
305
- finally {
306
- try {
307
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
308
- }
309
- finally { if (e_1) throw e_1.error; }
241
+ const { indexes } = item;
242
+ if (FilterUtility.matchAnyFilter(indexes, filters)) {
243
+ matches.push(item);
310
244
  }
311
- return matches;
312
- });
245
+ }
246
+ return matches;
313
247
  }
314
248
  /**
315
249
  * Creates an AsyncGenerator that returns each sorted index item given a specific sortProperty.
316
250
  * If a cursor is passed, the starting value (gt or lt) is derived from that.
317
251
  */
318
- getIndexIterator(tenant, startKey, queryOptions, options) {
319
- return __asyncGenerator(this, arguments, function* getIndexIterator_1() {
320
- var _a, e_2, _b, _c;
321
- const { sortProperty, sortDirection = SortDirection.Ascending, cursor } = queryOptions;
322
- const iteratorOptions = {
323
- gt: startKey
324
- };
325
- // if we are sorting in descending order we can iterate in reverse.
326
- if (sortDirection === SortDirection.Descending) {
327
- iteratorOptions.reverse = true;
328
- // if a cursor is provided and we are sorting in descending order, the startKey should be the upper bound.
329
- if (cursor !== undefined) {
330
- iteratorOptions.lt = startKey;
331
- delete iteratorOptions.gt;
332
- }
333
- }
334
- const sortPartition = yield __await(this.getIndexPartition(tenant, sortProperty));
335
- try {
336
- for (var _d = true, _e = __asyncValues(sortPartition.iterator(iteratorOptions, options)), _f; _f = yield __await(_e.next()), _a = _f.done, !_a; _d = true) {
337
- _c = _f.value;
338
- _d = false;
339
- const [_, val] = _c;
340
- const { indexes, messageCid } = JSON.parse(val);
341
- yield yield __await({ indexes, messageCid });
342
- }
343
- }
344
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
345
- finally {
346
- try {
347
- if (!_d && !_a && (_b = _e.return)) yield __await(_b.call(_e));
348
- }
349
- finally { if (e_2) throw e_2.error; }
252
+ async *getIndexIterator(tenant, startKey, queryOptions, options) {
253
+ const { sortProperty, sortDirection = SortDirection.Ascending, cursor } = queryOptions;
254
+ const iteratorOptions = {
255
+ gt: startKey
256
+ };
257
+ // if we are sorting in descending order we can iterate in reverse.
258
+ if (sortDirection === SortDirection.Descending) {
259
+ iteratorOptions.reverse = true;
260
+ // if a cursor is provided and we are sorting in descending order, the startKey should be the upper bound.
261
+ if (cursor !== undefined) {
262
+ iteratorOptions.lt = startKey;
263
+ delete iteratorOptions.gt;
350
264
  }
351
- });
265
+ }
266
+ const sortPartition = await this.getIndexPartition(tenant, sortProperty);
267
+ for await (const [_, val] of sortPartition.iterator(iteratorOptions, options)) {
268
+ const { indexes, messageCid } = JSON.parse(val);
269
+ yield { indexes, messageCid };
270
+ }
352
271
  }
353
272
  /**
354
273
  * Creates the starting point for a LevelDB query given an messageCid as a cursor and the indexed property.
@@ -394,151 +313,117 @@ export class IndexLevel {
394
313
  *
395
314
  * @throws {DwnErrorCode.IndexLevelInMemoryInvalidSortProperty} if an invalid sort property is provided.
396
315
  */
397
- queryWithInMemoryPaging(tenant, filters, queryOptions, options) {
398
- return __awaiter(this, void 0, void 0, function* () {
399
- const { sortProperty, sortDirection = SortDirection.Ascending, cursor: queryCursor, limit } = queryOptions;
400
- // we get the cursor start key here so that we match the failing behavior of `queryWithIteratorPaging`
401
- const cursorStartingKey = queryCursor ? this.createStartingKeyFromCursor(queryCursor) : undefined;
402
- // we create a matches map so that we can short-circuit matched items within the async single query below.
403
- const matches = new Map();
404
- // If the filter is empty, we just give it an empty filter so that we can iterate over all the items later in executeSingleFilterQuery().
405
- // We could do the iteration here, but it would be duplicating the same logic, so decided to just setup the data structure here.
406
- if (filters.length === 0) {
407
- filters = [{}];
408
- }
409
- try {
410
- yield Promise.all(filters.map(filter => {
411
- return this.executeSingleFilterQuery(tenant, filter, sortProperty, matches, options);
412
- }));
413
- }
414
- catch (error) {
415
- if (error.code === DwnErrorCode.IndexInvalidSortPropertyInMemory) {
416
- // return empty results if the sort property is invalid.
417
- return [];
418
- }
419
- }
420
- const sortedValues = [...matches.values()].sort((a, b) => this.sortItems(a, b, sortProperty, sortDirection));
421
- const start = cursorStartingKey !== undefined ? this.findCursorStartingIndex(sortedValues, sortDirection, sortProperty, cursorStartingKey) : 0;
422
- if (start < 0) {
423
- // if the provided cursor does not come before any of the results, we return no results
316
+ async queryWithInMemoryPaging(tenant, filters, queryOptions, options) {
317
+ const { sortProperty, sortDirection = SortDirection.Ascending, cursor: queryCursor, limit } = queryOptions;
318
+ // we get the cursor start key here so that we match the failing behavior of `queryWithIteratorPaging`
319
+ const cursorStartingKey = queryCursor ? this.createStartingKeyFromCursor(queryCursor) : undefined;
320
+ // we create a matches map so that we can short-circuit matched items within the async single query below.
321
+ const matches = new Map();
322
+ // If the filter is empty, we just give it an empty filter so that we can iterate over all the items later in executeSingleFilterQuery().
323
+ // We could do the iteration here, but it would be duplicating the same logic, so decided to just setup the data structure here.
324
+ if (filters.length === 0) {
325
+ filters = [{}];
326
+ }
327
+ try {
328
+ await Promise.all(filters.map(filter => {
329
+ return this.executeSingleFilterQuery(tenant, filter, sortProperty, matches, options);
330
+ }));
331
+ }
332
+ catch (error) {
333
+ if (error.code === DwnErrorCode.IndexInvalidSortPropertyInMemory) {
334
+ // return empty results if the sort property is invalid.
424
335
  return [];
425
336
  }
426
- const end = limit !== undefined ? start + limit : undefined;
427
- return sortedValues.slice(start, end);
428
- });
337
+ }
338
+ const sortedValues = [...matches.values()].sort((a, b) => this.sortItems(a, b, sortProperty, sortDirection));
339
+ const start = cursorStartingKey !== undefined ? this.findCursorStartingIndex(sortedValues, sortDirection, sortProperty, cursorStartingKey) : 0;
340
+ if (start < 0) {
341
+ // if the provided cursor does not come before any of the results, we return no results
342
+ return [];
343
+ }
344
+ const end = limit !== undefined ? start + limit : undefined;
345
+ return sortedValues.slice(start, end);
429
346
  }
430
347
  /**
431
348
  * Execute a filtered query against a single filter and return all results.
432
349
  */
433
- executeSingleFilterQuery(tenant, filter, sortProperty, matches, levelOptions) {
434
- return __awaiter(this, void 0, void 0, function* () {
435
- // Note: We have an array of Promises in order to support OR (anyOf) matches when given a list of accepted values for a property
436
- const filterPromises = [];
437
- // If the filter is empty, then we just iterate over one of the indexes that contains all the records and return all items.
438
- if (isEmptyObject(filter)) {
439
- const getAllItemsPromise = this.getAllItems(tenant, sortProperty);
440
- filterPromises.push(getAllItemsPromise);
441
- }
442
- // else the filter is not empty
443
- const searchFilter = FilterSelector.reduceFilter(filter);
444
- for (const propertyName in searchFilter) {
445
- const propertyFilter = searchFilter[propertyName];
446
- // We will find the union of these many individual queries later.
447
- if (FilterUtility.isEqualFilter(propertyFilter)) {
448
- // propertyFilter is an EqualFilter, meaning it is a non-object primitive type
449
- const exactMatchesPromise = this.filterExactMatches(tenant, propertyName, propertyFilter, levelOptions);
350
+ async executeSingleFilterQuery(tenant, filter, sortProperty, matches, levelOptions) {
351
+ // Note: We have an array of Promises in order to support OR (anyOf) matches when given a list of accepted values for a property
352
+ const filterPromises = [];
353
+ // If the filter is empty, then we just iterate over one of the indexes that contains all the records and return all items.
354
+ if (isEmptyObject(filter)) {
355
+ const getAllItemsPromise = this.getAllItems(tenant, sortProperty);
356
+ filterPromises.push(getAllItemsPromise);
357
+ }
358
+ // else the filter is not empty
359
+ const searchFilter = FilterSelector.reduceFilter(filter);
360
+ for (const propertyName in searchFilter) {
361
+ const propertyFilter = searchFilter[propertyName];
362
+ // We will find the union of these many individual queries later.
363
+ if (FilterUtility.isEqualFilter(propertyFilter)) {
364
+ // propertyFilter is an EqualFilter, meaning it is a non-object primitive type
365
+ const exactMatchesPromise = this.filterExactMatches(tenant, propertyName, propertyFilter, levelOptions);
366
+ filterPromises.push(exactMatchesPromise);
367
+ }
368
+ else if (FilterUtility.isOneOfFilter(propertyFilter)) {
369
+ // `propertyFilter` is a OneOfFilter
370
+ // Support OR matches by querying for each values separately, then adding them to the promises array.
371
+ for (const propertyValue of new Set(propertyFilter)) {
372
+ const exactMatchesPromise = this.filterExactMatches(tenant, propertyName, propertyValue, levelOptions);
450
373
  filterPromises.push(exactMatchesPromise);
451
374
  }
452
- else if (FilterUtility.isOneOfFilter(propertyFilter)) {
453
- // `propertyFilter` is a OneOfFilter
454
- // Support OR matches by querying for each values separately, then adding them to the promises array.
455
- for (const propertyValue of new Set(propertyFilter)) {
456
- const exactMatchesPromise = this.filterExactMatches(tenant, propertyName, propertyValue, levelOptions);
457
- filterPromises.push(exactMatchesPromise);
458
- }
459
- }
460
- else if (FilterUtility.isRangeFilter(propertyFilter)) {
461
- // `propertyFilter` is a `RangeFilter`
462
- const rangeMatchesPromise = this.filterRangeMatches(tenant, propertyName, propertyFilter, levelOptions);
463
- filterPromises.push(rangeMatchesPromise);
464
- }
465
375
  }
466
- // acting as an OR match for the property, any of the promises returning a match will be treated as a property match
467
- for (const promise of filterPromises) {
468
- const indexItems = yield promise;
469
- // reminder: the promise returns a list of IndexedItem satisfying a particular property match
470
- for (const indexedItem of indexItems) {
471
- // short circuit: if a data is already included to the final matched key set (by a different `Filter`),
472
- // no need to evaluate if the data satisfies this current filter being evaluated
473
- // otherwise check that the item is a match.
474
- if (matches.has(indexedItem.messageCid) || !FilterUtility.matchFilter(indexedItem.indexes, filter)) {
475
- continue;
476
- }
477
- // ensure that each matched item has the sortProperty, otherwise fail the entire query.
478
- if (indexedItem.indexes[sortProperty] === undefined) {
479
- throw new DwnError(DwnErrorCode.IndexInvalidSortPropertyInMemory, `invalid sort property ${sortProperty}`);
480
- }
481
- matches.set(indexedItem.messageCid, indexedItem);
482
- }
376
+ else if (FilterUtility.isRangeFilter(propertyFilter)) {
377
+ // `propertyFilter` is a `RangeFilter`
378
+ const rangeMatchesPromise = this.filterRangeMatches(tenant, propertyName, propertyFilter, levelOptions);
379
+ filterPromises.push(rangeMatchesPromise);
483
380
  }
484
- });
485
- }
486
- getAllItems(tenant, sortProperty) {
487
- return __awaiter(this, void 0, void 0, function* () {
488
- var _a, e_3, _b, _c;
489
- const filterPartition = yield this.getIndexPartition(tenant, sortProperty);
490
- const items = [];
491
- try {
492
- for (var _d = true, _e = __asyncValues(filterPartition.iterator()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
493
- _c = _f.value;
494
- _d = false;
495
- const [_key, value] = _c;
496
- items.push(JSON.parse(value));
497
- }
498
- }
499
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
500
- finally {
501
- try {
502
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
503
- }
504
- finally { if (e_3) throw e_3.error; }
381
+ }
382
+ // acting as an OR match for the property, any of the promises returning a match will be treated as a property match
383
+ for (const promise of filterPromises) {
384
+ const indexItems = await promise;
385
+ // reminder: the promise returns a list of IndexedItem satisfying a particular property match
386
+ for (const indexedItem of indexItems) {
387
+ // short circuit: if a data is already included to the final matched key set (by a different `Filter`),
388
+ // no need to evaluate if the data satisfies this current filter being evaluated
389
+ // otherwise check that the item is a match.
390
+ if (matches.has(indexedItem.messageCid) || !FilterUtility.matchFilter(indexedItem.indexes, filter)) {
391
+ continue;
392
+ }
393
+ // ensure that each matched item has the sortProperty, otherwise fail the entire query.
394
+ if (indexedItem.indexes[sortProperty] === undefined) {
395
+ throw new DwnError(DwnErrorCode.IndexInvalidSortPropertyInMemory, `invalid sort property ${sortProperty}`);
396
+ }
397
+ matches.set(indexedItem.messageCid, indexedItem);
505
398
  }
506
- return items;
507
- });
399
+ }
400
+ }
401
+ async getAllItems(tenant, sortProperty) {
402
+ const filterPartition = await this.getIndexPartition(tenant, sortProperty);
403
+ const items = [];
404
+ for await (const [_key, value] of filterPartition.iterator()) {
405
+ items.push(JSON.parse(value));
406
+ }
407
+ return items;
508
408
  }
509
409
  /**
510
410
  * Returns items that match the exact property and value.
511
411
  */
512
- filterExactMatches(tenant, propertyName, propertyValue, options) {
513
- return __awaiter(this, void 0, void 0, function* () {
514
- var _a, e_4, _b, _c;
515
- const matchPrefix = IndexLevel.keySegmentJoin(IndexLevel.encodeValue(propertyValue));
516
- const iteratorOptions = {
517
- gt: matchPrefix
518
- };
519
- const filterPartition = yield this.getIndexPartition(tenant, propertyName);
520
- const matches = [];
521
- try {
522
- for (var _d = true, _e = __asyncValues(filterPartition.iterator(iteratorOptions, options)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
523
- _c = _f.value;
524
- _d = false;
525
- const [key, value] = _c;
526
- // immediately stop if we arrive at an index that contains a different property value
527
- if (!key.startsWith(matchPrefix)) {
528
- break;
529
- }
530
- matches.push(JSON.parse(value));
531
- }
532
- }
533
- catch (e_4_1) { e_4 = { error: e_4_1 }; }
534
- finally {
535
- try {
536
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
537
- }
538
- finally { if (e_4) throw e_4.error; }
539
- }
540
- return matches;
541
- });
412
+ async filterExactMatches(tenant, propertyName, propertyValue, options) {
413
+ const matchPrefix = IndexLevel.keySegmentJoin(IndexLevel.encodeValue(propertyValue));
414
+ const iteratorOptions = {
415
+ gt: matchPrefix
416
+ };
417
+ const filterPartition = await this.getIndexPartition(tenant, propertyName);
418
+ const matches = [];
419
+ for await (const [key, value] of filterPartition.iterator(iteratorOptions, options)) {
420
+ // immediately stop if we arrive at an index that contains a different property value
421
+ if (!key.startsWith(matchPrefix)) {
422
+ break;
423
+ }
424
+ matches.push(JSON.parse(value));
425
+ }
426
+ return matches;
542
427
  }
543
428
  /**
544
429
  * Returns items that match the range filter.
@@ -547,51 +432,36 @@ export class IndexLevel {
547
432
  * of the form `<encodedValue>\x00<messageCid>` are naturally included in the range scan,
548
433
  * eliminating the need for a separate exact-match query.
549
434
  */
550
- filterRangeMatches(tenant, propertyName, rangeFilter, options) {
551
- return __awaiter(this, void 0, void 0, function* () {
552
- var _a, e_5, _b, _c;
553
- const iteratorOptions = {};
554
- for (const comparator in rangeFilter) {
555
- const comparatorName = comparator;
556
- const encodedValue = IndexLevel.encodeValue(rangeFilter[comparatorName]);
557
- if (comparatorName === 'lte') {
558
- // Extend the lte bound so that composite keys `<encodedValue>\x00<messageCid>` are included.
559
- // Since \x00 < \xff, any key starting with encodedValue followed by the \x00 delimiter
560
- // will be lexicographically less than encodedValue + \xff.
561
- iteratorOptions[comparatorName] = encodedValue + '\xff';
562
- }
563
- else {
564
- iteratorOptions[comparatorName] = encodedValue;
565
- }
435
+ async filterRangeMatches(tenant, propertyName, rangeFilter, options) {
436
+ const iteratorOptions = {};
437
+ for (const comparator in rangeFilter) {
438
+ const comparatorName = comparator;
439
+ const encodedValue = IndexLevel.encodeValue(rangeFilter[comparatorName]);
440
+ if (comparatorName === 'lte') {
441
+ // Extend the lte bound so that composite keys `<encodedValue>\x00<messageCid>` are included.
442
+ // Since \x00 < \xff, any key starting with encodedValue followed by the \x00 delimiter
443
+ // will be lexicographically less than encodedValue + \xff.
444
+ iteratorOptions[comparatorName] = encodedValue + '\xff';
566
445
  }
567
- // if there is no lower bound specified (`gt` or `gte`), we need to iterate from the upper bound,
568
- // so that we will iterate over all the matches before hitting mismatches.
569
- if (iteratorOptions.gt === undefined && iteratorOptions.gte === undefined) {
570
- iteratorOptions.reverse = true;
571
- }
572
- const matches = [];
573
- const filterPartition = yield this.getIndexPartition(tenant, propertyName);
574
- try {
575
- for (var _d = true, _e = __asyncValues(filterPartition.iterator(iteratorOptions, options)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
576
- _c = _f.value;
577
- _d = false;
578
- const [key, value] = _c;
579
- // if "greater-than" is specified, skip all keys that contain the exact value given in the "greater-than" condition
580
- if ('gt' in rangeFilter && this.extractIndexValueFromKey(key) === IndexLevel.encodeValue(rangeFilter.gt)) {
581
- continue;
582
- }
583
- matches.push(JSON.parse(value));
584
- }
446
+ else {
447
+ iteratorOptions[comparatorName] = encodedValue;
585
448
  }
586
- catch (e_5_1) { e_5 = { error: e_5_1 }; }
587
- finally {
588
- try {
589
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
590
- }
591
- finally { if (e_5) throw e_5.error; }
449
+ }
450
+ // if there is no lower bound specified (`gt` or `gte`), we need to iterate from the upper bound,
451
+ // so that we will iterate over all the matches before hitting mismatches.
452
+ if (iteratorOptions.gt === undefined && iteratorOptions.gte === undefined) {
453
+ iteratorOptions.reverse = true;
454
+ }
455
+ const matches = [];
456
+ const filterPartition = await this.getIndexPartition(tenant, propertyName);
457
+ for await (const [key, value] of filterPartition.iterator(iteratorOptions, options)) {
458
+ // if "greater-than" is specified, skip all keys that contain the exact value given in the "greater-than" condition
459
+ if ('gt' in rangeFilter && this.extractIndexValueFromKey(key) === IndexLevel.encodeValue(rangeFilter.gt)) {
460
+ continue;
592
461
  }
593
- return matches;
594
- });
462
+ matches.push(JSON.parse(value));
463
+ }
464
+ return matches;
595
465
  }
596
466
  /**
597
467
  * Sorts Items lexicographically in ascending or descending order given a specific indexName, using the messageCid as a tie breaker.
@@ -639,16 +509,14 @@ export class IndexLevel {
639
509
  /**
640
510
  * Gets the indexes given an messageCid. This is a reverse lookup to construct starting keys, as well as deleting indexed items.
641
511
  */
642
- getIndexes(tenant, messageCid) {
643
- return __awaiter(this, void 0, void 0, function* () {
644
- const indexesLookupPartition = yield this.getIndexesLookupPartition(tenant);
645
- const serializedIndexes = yield indexesLookupPartition.get(messageCid);
646
- if (serializedIndexes === undefined) {
647
- // invalid messageCid
648
- return;
649
- }
650
- return JSON.parse(serializedIndexes);
651
- });
512
+ async getIndexes(tenant, messageCid) {
513
+ const indexesLookupPartition = await this.getIndexesLookupPartition(tenant);
514
+ const serializedIndexes = await indexesLookupPartition.get(messageCid);
515
+ if (serializedIndexes === undefined) {
516
+ // invalid messageCid
517
+ return;
518
+ }
519
+ return JSON.parse(serializedIndexes);
652
520
  }
653
521
  /**
654
522
  * Given a key from an indexed partitioned property key.
@@ -660,6 +528,10 @@ export class IndexLevel {
660
528
  const [value] = key.split(IndexLevel.delimiter);
661
529
  return value;
662
530
  }
531
+ /**
532
+ * Joins the given values using the `\x00` (\u0000) character.
533
+ */
534
+ static delimiter = `\x00`;
663
535
  static keySegmentJoin(...values) {
664
536
  return values.join(IndexLevel.delimiter);
665
537
  }
@@ -694,292 +566,6 @@ export class IndexLevel {
694
566
  }
695
567
  }
696
568
  // =========================================================================
697
- // Compound index methods
698
- // =========================================================================
699
- /**
700
- * Gets the compound index partition for a given compound index definition.
701
- * Compound index sublevels use the naming convention `__compound:<name>__`.
702
- */
703
- getCompoundIndexPartition(tenant, compoundIndex) {
704
- return __awaiter(this, void 0, void 0, function* () {
705
- const partitionName = `__compound:${compoundIndex.name}__`;
706
- return (yield this.db.partition(tenant)).partition(partitionName);
707
- });
708
- }
709
- /**
710
- * Builds a compound index key from the given indexes and compound index definition.
711
- *
712
- * Key format: `<prop1>\x01<prop2>\x01...\x01<sortValue>\x00<messageCid>`
713
- *
714
- * @returns the compound key, or undefined if the indexes don't contain all required properties.
715
- */
716
- static buildCompoundKey(messageCid, indexes, compoundIndex) {
717
- const segments = [];
718
- for (const property of compoundIndex.properties) {
719
- const value = indexes[property];
720
- if (value === undefined || Array.isArray(value)) {
721
- return undefined; // compound indexes don't support array values or missing properties
722
- }
723
- segments.push(IndexLevel.encodeValue(value));
724
- }
725
- const sortValue = indexes[compoundIndex.sortProperty];
726
- if (sortValue === undefined || Array.isArray(sortValue)) {
727
- return undefined;
728
- }
729
- // join prefix segments with \x01, then append sort value and messageCid with the standard delimiters
730
- const prefixPart = segments.join(COMPOUND_SEGMENT_SEPARATOR);
731
- const sortPart = IndexLevel.encodeValue(sortValue);
732
- return prefixPart + COMPOUND_SEGMENT_SEPARATOR + sortPart + IndexLevel.delimiter + messageCid;
733
- }
734
- /**
735
- * Builds the prefix portion of a compound key from filter values (without the sort/messageCid suffix).
736
- * Used for range scans: all entries with this prefix match the filter.
737
- */
738
- static buildCompoundPrefix(filter, compoundIndex) {
739
- const segments = [];
740
- for (const property of compoundIndex.properties) {
741
- const filterValue = filter[property];
742
- if (filterValue === undefined || typeof filterValue === 'object') {
743
- return undefined; // compound prefix only works with equality filters
744
- }
745
- segments.push(IndexLevel.encodeValue(filterValue));
746
- }
747
- return segments.join(COMPOUND_SEGMENT_SEPARATOR) + COMPOUND_SEGMENT_SEPARATOR;
748
- }
749
- /**
750
- * Creates a put operation for a compound index entry.
751
- * Returns undefined if the indexes don't contain all required compound index properties.
752
- */
753
- createCompoundIndexPutOperation(tenant, item, compoundIndex) {
754
- const key = IndexLevel.buildCompoundKey(item.messageCid, item.indexes, compoundIndex);
755
- if (key === undefined) {
756
- return undefined;
757
- }
758
- return this.createOperationForPartition(tenant, `__compound:${compoundIndex.name}__`, {
759
- type: 'put',
760
- key,
761
- value: JSON.stringify(item),
762
- });
763
- }
764
- /**
765
- * Creates a delete operation for a compound index entry.
766
- * Returns undefined if the indexes don't contain all required compound index properties.
767
- */
768
- createCompoundIndexDeleteOperation(tenant, messageCid, indexes, compoundIndex) {
769
- const key = IndexLevel.buildCompoundKey(messageCid, indexes, compoundIndex);
770
- if (key === undefined) {
771
- return undefined;
772
- }
773
- return this.createOperationForPartition(tenant, `__compound:${compoundIndex.name}__`, {
774
- type: 'del',
775
- key,
776
- });
777
- }
778
- /**
779
- * Generic helper to create a batch operation for any named partition under a tenant.
780
- */
781
- createOperationForPartition(tenant, partitionName, operation) {
782
- return __awaiter(this, void 0, void 0, function* () {
783
- const tenantPartition = yield this.db.partition(tenant);
784
- return tenantPartition.createPartitionOperation(partitionName, operation);
785
- });
786
- }
787
- /**
788
- * Selects the best compound index that covers the given filter and sort requirements.
789
- *
790
- * A compound index "covers" a query when:
791
- * 1. Every property in the compound index definition is present in the filter as an equality filter.
792
- * 2. The compound index's sort property matches the query's sort property.
793
- *
794
- * Among multiple matching compound indexes, the one with the most properties is preferred
795
- * (more specific = fewer false positives in the prefix scan).
796
- */
797
- selectCompoundIndex(filter, queryOptions) {
798
- let bestMatch;
799
- let bestPropertyCount = 0;
800
- for (const compoundIndex of this._compoundIndexes) {
801
- // check that the sort property matches
802
- if (compoundIndex.sortProperty !== queryOptions.sortProperty) {
803
- continue;
804
- }
805
- // check that all compound properties are present in the filter as equality filters
806
- let allPropertiesMatch = true;
807
- for (const property of compoundIndex.properties) {
808
- const filterValue = filter[property];
809
- if (filterValue === undefined || typeof filterValue === 'object') {
810
- allPropertiesMatch = false;
811
- break;
812
- }
813
- }
814
- if (allPropertiesMatch && compoundIndex.properties.length > bestPropertyCount) {
815
- bestMatch = compoundIndex;
816
- bestPropertyCount = compoundIndex.properties.length;
817
- }
818
- }
819
- return bestMatch;
820
- }
821
- /**
822
- * Queries using a compound index. This is the most efficient query strategy: a single LevelDB
823
- * range scan that filters, sorts, and paginates all at once.
824
- *
825
- * The compound key encodes the filter properties as a prefix and the sort property as a suffix,
826
- * so iterating over keys with the filter prefix yields results in sort order.
827
- *
828
- * Any remaining filter properties not covered by the compound index are verified in memory.
829
- */
830
- queryWithCompoundIndex(tenant, filter, queryOptions, compoundIndex, options) {
831
- return __awaiter(this, void 0, void 0, function* () {
832
- var _a, e_6, _b, _c;
833
- const { sortDirection = SortDirection.Ascending, cursor, limit } = queryOptions;
834
- const prefix = IndexLevel.buildCompoundPrefix(filter, compoundIndex);
835
- if (prefix === undefined) {
836
- // should not happen since selectCompoundIndex already validated, but guard against it
837
- return this.queryWithIteratorPaging(tenant, [filter], queryOptions, options);
838
- }
839
- const partition = yield this.getCompoundIndexPartition(tenant, compoundIndex);
840
- // determine the iterator bounds from the prefix
841
- const iteratorOptions = {};
842
- if (cursor !== undefined) {
843
- // build the full compound key for the cursor position
844
- const cursorSortEncoded = IndexLevel.encodeValue(cursor.value);
845
- const cursorKey = prefix + cursorSortEncoded + IndexLevel.delimiter + cursor.messageCid;
846
- if (sortDirection === SortDirection.Ascending) {
847
- iteratorOptions.gt = cursorKey;
848
- // upper bound: everything with this prefix (prefix + \xff is past all valid compound keys with this prefix)
849
- iteratorOptions.lt = prefix + '\xff';
850
- }
851
- else {
852
- iteratorOptions.lt = cursorKey;
853
- iteratorOptions.gt = prefix;
854
- iteratorOptions.reverse = true;
855
- }
856
- }
857
- else {
858
- if (sortDirection === SortDirection.Ascending) {
859
- iteratorOptions.gt = prefix;
860
- iteratorOptions.lt = prefix + '\xff';
861
- }
862
- else {
863
- // for descending without cursor, start from the end of the prefix range
864
- iteratorOptions.gt = prefix;
865
- iteratorOptions.lt = prefix + '\xff';
866
- iteratorOptions.reverse = true;
867
- }
868
- }
869
- // determine which filter properties are NOT covered by the compound index
870
- // (need in-memory verification for these)
871
- // NOTE: the compound index equality properties are fully covered by the prefix scan,
872
- // but the sort property is only covered for ordering — any range filter on the sort
873
- // property must still be applied as a residual filter.
874
- const coveredEqualityProperties = new Set(compoundIndex.properties);
875
- const residualFilter = {};
876
- let hasResidualFilter = false;
877
- for (const property in filter) {
878
- if (!coveredEqualityProperties.has(property)) {
879
- residualFilter[property] = filter[property];
880
- hasResidualFilter = true;
881
- }
882
- }
883
- const matches = [];
884
- try {
885
- for (var _d = true, _e = __asyncValues(partition.iterator(iteratorOptions, options)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
886
- _c = _f.value;
887
- _d = false;
888
- const [_key, value] = _c;
889
- if (limit !== undefined && matches.length === limit) {
890
- break;
891
- }
892
- const item = JSON.parse(value);
893
- // verify any residual filter properties in memory
894
- if (hasResidualFilter && !FilterUtility.matchFilter(item.indexes, residualFilter)) {
895
- continue;
896
- }
897
- matches.push(item);
898
- }
899
- }
900
- catch (e_6_1) { e_6 = { error: e_6_1 }; }
901
- finally {
902
- try {
903
- if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
904
- }
905
- finally { if (e_6) throw e_6.error; }
906
- }
907
- return matches;
908
- });
909
- }
910
- /**
911
- * Counts items matching a compound index prefix without loading full records.
912
- * Iterates only keys (not values) for maximum efficiency.
913
- */
914
- countWithCompoundIndex(tenant, filter, compoundIndex, options) {
915
- return __awaiter(this, void 0, void 0, function* () {
916
- var _a, e_7, _b, _c, _d, e_8, _e, _f;
917
- const prefix = IndexLevel.buildCompoundPrefix(filter, compoundIndex);
918
- if (prefix === undefined) {
919
- // fallback
920
- const results = yield this.query(tenant, [filter], { sortProperty: compoundIndex.sortProperty }, options);
921
- return results.length;
922
- }
923
- const partition = yield this.getCompoundIndexPartition(tenant, compoundIndex);
924
- // determine which filter properties are NOT covered by the compound index
925
- // (same logic as queryWithCompoundIndex: sort property range filters are residual)
926
- const coveredEqualityProperties = new Set(compoundIndex.properties);
927
- let hasResidualFilter = false;
928
- const residualFilter = {};
929
- for (const property in filter) {
930
- if (!coveredEqualityProperties.has(property)) {
931
- residualFilter[property] = filter[property];
932
- hasResidualFilter = true;
933
- }
934
- }
935
- const iteratorOptions = {
936
- gt: prefix,
937
- lt: prefix + '\xff',
938
- };
939
- let count = 0;
940
- if (hasResidualFilter) {
941
- try {
942
- // must read values to check residual filter
943
- for (var _g = true, _h = __asyncValues(partition.iterator(iteratorOptions, options)), _j; _j = yield _h.next(), _a = _j.done, !_a; _g = true) {
944
- _c = _j.value;
945
- _g = false;
946
- const [_key, value] = _c;
947
- const item = JSON.parse(value);
948
- if (FilterUtility.matchFilter(item.indexes, residualFilter)) {
949
- count++;
950
- }
951
- }
952
- }
953
- catch (e_7_1) { e_7 = { error: e_7_1 }; }
954
- finally {
955
- try {
956
- if (!_g && !_a && (_b = _h.return)) yield _b.call(_h);
957
- }
958
- finally { if (e_7) throw e_7.error; }
959
- }
960
- }
961
- else {
962
- try {
963
- // no residual filter — iterate keys via iterator without parsing values
964
- for (var _k = true, _l = __asyncValues(partition.iterator(iteratorOptions, options)), _m; _m = yield _l.next(), _d = _m.done, !_d; _k = true) {
965
- _f = _m.value;
966
- _k = false;
967
- const [_key, _value] = _f;
968
- count++;
969
- }
970
- }
971
- catch (e_8_1) { e_8 = { error: e_8_1 }; }
972
- finally {
973
- try {
974
- if (!_k && !_d && (_e = _l.return)) yield _e.call(_l);
975
- }
976
- finally { if (e_8) throw e_8.error; }
977
- }
978
- }
979
- return count;
980
- });
981
- }
982
- // =========================================================================
983
569
  // Query strategy selection
984
570
  // =========================================================================
985
571
  static shouldQueryWithInMemoryPaging(filters, queryOptions) {
@@ -1011,8 +597,4 @@ export class IndexLevel {
1011
597
  return false;
1012
598
  }
1013
599
  }
1014
- /**
1015
- * Joins the given values using the `\x00` (\u0000) character.
1016
- */
1017
- IndexLevel.delimiter = `\x00`;
1018
600
  //# sourceMappingURL=index-level.js.map